Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test the methods of a class whose constructor take some arguments?

I have a class of form something like this:

class A{  
    public function __constructor(classB b , classC c){
    //
    }

    public function getSum(var1, var2){
        return var1+var2;
    }
}

My test case class is something like this:

use A;   
class ATest extends PHPUnit_Framework_TestCase{  

    public function testGetSum{  
        $a = new A();
        $this->assertEquals(3, $a->getSum(1,2));  
    }  
}  

However when I run the phpunit, it throws some error like:

Missing argument 1 for \..\::__construct(), called in /../A.php on line 5

Even if I provide the arguments, it throws the same error but in different file.
say, I instantiate by $a = new A(new classB(), new classC());

Then, I get the same error for the constructor of classB(the constructor of classB has similar form to that of A).

Missing argument 1 for \..\::__construct(), called in /../B.php on line 10

Is there any other way, I can test the function or something which I am missing.

I don't want to test by using mock (getMockBuilder(),setMethods(),getMock()) as it seems to defy the whole purpose of unit testing.

like image 430
Sunil Chaudhary Avatar asked Sep 08 '16 11:09

Sunil Chaudhary


People also ask

How do you test a constructor in unit testing?

To test that a constructor does its job (of making the class invariant true), you have to first use the constructor in creating a new object and then test that every field of the object has the correct value. Yes, you need need an assertEquals call for each field.

Should we write unit test for constructors?

because your operation should fail if that object is null which makes sense the "behavior" fails and we should unit test that rather the actual constructors.

Can JUnit test have constructor?

JUnit provides lot of methods to test our cases. We can test the constructor of a class using the same techniques we have used in our previous examples. Sometimes we need to initialize the objects and we do them in a constructor. In JUnit we can also do same using the @Before method.

Can we write test cases for constructor in Java?

The constructor has no logic besides setting up the fields. So the only thing you can test is that the same values passed into the constructor are accessible via getter methods.


2 Answers

The basic idea behind unit test it to test a class / method itself, not dependencies of this class. In order to unit test you class A you should not use real instances of your constructor arguments but use mocks instead. PHPUnit provides nice way to create ones, so:

use A;   
class ATest extends PHPUnit_Framework_TestCase{  

    public function testGetSum{  
        $arg1Mock = $this->getMock('classB'); //use fully qualified class name
        $arg2Mock = $this->getMockBuilder('classC')
            ->disableOriginalConstructor()
            ->getMock(); //use mock builder in case classC constructor requires additional arguments
        $a = new A($arg1Mock, $arg2Mock);
        $this->assertEquals(3, $a->getSum(1,2));  
    }  
}  

Note: If you won't be using mock's here but a real classB and classC instances it won't be unit test anymore - it will be a functional test

like image 142
Tomasz Madeyski Avatar answered Nov 07 '22 04:11

Tomasz Madeyski


You could tell to PHPUnit which method you want to mock of a specified class, with the methods setMethods. From the doc:

setMethods(array $methods) can be called on the Mock Builder object to specify the methods that are to be replaced with a configurable test double. The behavior of the other methods is not changed. If you call setMethods(null), then no methods will be replaced.

So you can construct your class without replacing any methods but bypass the construct as following (working) code:

public function testGetSum(){
    $a = $this->getMockBuilder(A::class)
        ->setMethods(null)
        ->disableOriginalConstructor()
        ->getMock();

    $this->assertEquals(3, $a->getSum(1,2));
}

Hope this help

like image 32
Matteo Avatar answered Nov 07 '22 03:11

Matteo