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

10,773

Solution 1

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

Solution 2

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

Share:
10,773
Sunil Chaudhary
Author by

Sunil Chaudhary

Brief Summary Software Developer with 5 years of experience building highly performant and scalable frontend applications using the latest technologies (expertise in Javascript - ReactJs + Redux). Passionate about learning new stuff and implementing them to make everyday life more comfortable. Worked on diverse projects including but not limited to website development, performance optimization, Wordpress CMS, analytics tool development, widgetized framework development, developing automated tools to create dashboards etc. Ping me anytime for probono consulting, advice on frontend interviews preparation or some general chit-chat. Happy to Help :-) Work History Working in digital payments and finance services (PhonePe Pvt. Ltd. (Owned by Walmart) for last 1 year Worked in fast paced startup in travel domain (Goomo) for about 2 years Worked in a startup in health domain (Practo) for about a year Education B.tech, Computer Science and Engineering IIT Kanpur (2012-16) Expertise Javascript HTML CSS ReactJs Redux and few other stuff Contact My email id is [email protected]

Updated on June 13, 2022

Comments

  • Sunil Chaudhary
    Sunil Chaudhary almost 2 years

    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.

  • arqam
    arqam over 4 years
    What if we need to mock a method in Class 'A' also, then can we do anything?