How to unit-test protected methods? - phpunit

Is there a way to unit-test protected or private methods of a class? As it is now, I'm making a lot of methods public in order to be able to test them, which breaks the API.
Edit: Actually answered here: Best practices to test protected methods with PHPUnit

You can access your private and/or protected method by using the ReflectionMethod class followed by invoke method, but to invoke the method you also need an instance of your class which in certain situations isn't possible. Based on this one nice example that works is this one:
Get a mock of your class:
$mockedInstance = $this->getMockBuilder(YourClass::class)
->disableOriginalConstructor() // you may need the constructor on integration tests only
->getMock();
Get your method to be tested:
$reflectedMethod = new \ReflectionMethod(
YourClass::class,
'yourMethod'
);
$reflectedMethod->setAccessible(true);
Call your private/protected method:
$reflectedMethod->invokeArgs( //use invoke method if you don't have parameters on your method
$mockedInstance,
[$param1, ..., $paramN]
);

For protected methods, you can subclass the class under test:
class Foo
{
protected function doThings($foo)
{
//...
}
}
class _Foo extends Foo
{
public function _doThings($foo)
{
return $this->doThings($foo);
}
}
and in the test:
$sut = new _Foo();
$this->assertEquals($expected, $sut->_doThings($stuff));
With private methods it is a bit more difficult, you could use the Reflection API to call protected methods. Also, there is an argument that private methods should only come into existence during refactoring so should be covered by the public methods that call them, but that only really works if you did test-first to start with and in real life we have legacy code to deal with ;)
Links for the reflection api:
http://php.net/manual/en/reflectionmethod.setaccessible.php
Also, this link looks useful for this purpose:
https://jtreminio.com/2013/03/unit-testing-tutorial-part-3-testing-protected-private-methods-coverage-reports-and-crap/

Related

PHPUnit test if class methods were called

I have model class that calls mailer class inside one of its methods:
class someModel{
public function sendEmail($data){
$mailer = new Mailer();
$mailer->setFrom($data['from']);
$mailer->setTo($data['to']);
$mailer->setSubject($data['subject']);
return $mailer->send();
}
}
How can I test sendEmail method? Maybe I should mock mailer class and check if all these mailer methods were called in sendMail method?
Your help would be appreciated.
IMO wrapping the Mailer class does not solve the problem you're facing, which is you don't have control over the Mail instance being used.
The problem comes from creating the dependencies inside the object that needs them instead of injecting them externally like this:
class someModel{
private $mailer;
public function __construct(Mailer $mailer) {
$this->mailer = $mailer;
}
public function sendEmail($data){
$this->mailer->setFrom($data['from']);
$this->mailer->setTo($data['to']);
$this->mailer->setSubject($data['subject']);
return $this->mailer->send();
}
}
When creating the someModel instance, you must pass a Mail instance (which is an external dependency). And in the test you can pass a Mail mock that will check that the correct calls are being made.
Alternative:
If you feel that injecting a Mail instance is bad (maybe because there are lots of someModel instances), or you just can't change your code this way, then you could use a Services repository, that will keep a single Mail instance and that allows you to set it externally (again, in the test you would set a mock).
Try a simple one like Pimple.
I would (and have in my own code with Mailer!) wrap your instance of Mailer inside a class that you write. In other words, make your own Email class that uses Mailer under the hood. That allows you to simplify the interface of Mailer down to just what you need and more easily mock it. It also gives you the ability to replace Mailer seamlessly at a later date.
The most important thing to keep in mind when you wrap classes to hide external dependencies is keep the wrapper class simple. It's only purpose is to let you swap out the Email libraries class, not provide any complicated logic.
Example:
class Emailer {
private $mailer = new Mailer();
public function send($to, $from, $subject, $data) {
$this->mailer->setFrom($from);
$this->mailer->setTo($to);
...
return $mailer->send();
}
}
class EmailerMock extends Emailer {
public function send($to, $from, $subject, $data) {
... Store whatever test data you want to verify ...
}
//Accessors for testing the right data was sent in your unit test
public function getTo() { ... }
...
}
I follow the same pattern for all classes/libraries that want to touch things external to my software. Other good candidates are database connections, web services connections, cache connections, etc.
EDIT:
gontrollez raised a good point in his answer about dependency injection. I failed to explicitly mention it, but after creating the wrapper the way you would want to use some form of dependency injection to get it into the code where you want to use it. Passing in the instance makes it possible to setup the test case with a Mocked instance.
One method of doing this is passing in the instance to the constructor as gontrollez recommends. There are a lot of cases where that is the best way to do it. However, for "external services" that I am mocking I found that method became tedious because so many classes ended up needing the instance passed in. Consider for example a database driver that you want to Mock for your tests, but you use in many many different classes. So instead what I do is create a singleton class with a method that lets me mock the whole thing at once. Any client code can then just use the singleton to get access to a service without knowing that it was mocked. It looked something like this:
class Externals {
static private $instance = null;
private $db = null;
private $email = null;
...
private function __construct() {
$this->db = new RealDB();
$this->mail = new RealMail();
}
static function initTest() {
self::get(); //Ensure instance created
$db = new MockDB();
$email = new MockEmail();
}
static function get() {
if(!self::$instance)
self::$instance = new Externals();
return self::$instance;
}
function getDB() { return $this->db; }
function getMail() { return $this->mail; }
....
}
Then you can use phpunit's bootstrap file feature to call Externals::initTest() and all your tests will be setup with the mocked externals!
First, as RyanW says, you should write your own wrapper for Mailer.
Second, to test it, use a mock:
<?php
class someModelTest extends \PHPUnit_Framework_TestCase
{
public function testSendEmail()
{
// Mock the class so we can verify that the methods are called
$model = $this->getMock('someModel', array('setFrom', 'setTo', 'setSubject', 'send'));
$controller->expects($this->once())
->method('setFrom');
$controller->expects($this->once())
->method('setTo');
$controller->expects($this->once())
->method('setSubject');
$controller->expects($this->once())
->method('send');
$model->sendEmail();
}
}
The above code is untested, but it basically mocks the someModel class, creating dummy functions for each each function called within sendEmail. It then tests to make sure each of the functions called by sendEmail is called exactly once when sendEmail is called.
See the PHPUnit docs for more info on mocking.

In phpunit what is the difference between __construct versus setup?

I am curious to know it is good practice to create object in test class __construct or we should always use setup/teardown approach ( or setUpBeforeClass/tearDownAfterClass approach)?
I aware of the fact set/teardown gets called for each test so will it do any good if I put my object creation code in it? e.g.
//mytestclass.php
class MyTestClass extends PHPUnit_Framework_TestCase
{
private $obj;
protected function setUp()
{
$this->obj = new FooClass();
}
public testFooObj()
{
//assertions for $this->obj
}
...
}
what could be the issues if I create object in constructor like this:
class MyTestClass extends PHPUnit_Framework_TestCase
{
private $obj;
protected function __construct()
{
$this->obj = new FooClass();
}
public testFooObj()
{
//assertions for $this->obj
}
...
}
I tried googling around as well as PHPUnit documentation couldn't get much information about, Can you please help me to understand which one is good practice?
setUp() gets called before each of your tests is ran. __construct() happens when your class is instantiated. So if you have multiple tests and they use local properties and modify them, using setUp() you can ensure that they are the same before each test is ran. The opposite of setUp() is tearDown() where you can ensure that test data gets cleaned up after each test.
As I have just found out, implementing the default class constructor instead of the setupBeforeClass() method breaks the #dataProvider annotations (probably all kinds of annotations), yielding a "Missing argument" exception for any parameterized tests.
Missing argument 1 for AppBundle\Tests\Service\InvitationVerifierTest::testDireccionInvalida()
Replacing public function __construct() for public static function setUpBeforeClass() gets rid of the exception. So there it goes, favor the setupBeforeClass() method over the regular constructor.
PHPUnit version 4.5.0

Handling specimen creation inconsistencies between AutoFixture and Moq

I am using AutoMoqCustomization in my test conventions.
Consider the code below. Everything works great until I add a constructor to one of the concrete classes. When I do, I get "could not find a parameterless constructor". We know AutoFixture doesn't have an issue with the constructor because it delivered me the test object one which proved to be assignable from IThings... no failure there. So it must be moq.
This makes some sense because I assume builder was generated by moq and passed into the GetCommands method. So I think I can see that control has been passed from AutoFixture to moq at that point.
That takes care of the why, but what should I do about it? Is there a way to instruct moq on how to deal with the ThingOne or is there a way to instruct AutoFixture to ignore moq for IThingBuilders and instead do something Fixtury?
public class TestClass
{
public interface IThingBuilders
{
T1 Build<T1>() where T1 : IThings;
}
public interface IThings
{
}
public class ThingOne : IThings
{
public ThingOne(string someparam)
{
}
}
public class ThingTwo : IThings
{
}
public class SomeClass
{
public List<IThings> GetCommands(IThingBuilders builder)
{
var newlist = new List<IThings>();
newlist.Add(builder.Build<ThingOne>());
newlist.Add(builder.Build<ThingTwo>());
return newlist;
}
}
[Theory, BasicConventions]
public void WhyCannotInstantiateProxyOfClass(ThingOne one, ThingTwo two, IThingBuilders builder, SomeClass sut)
{
Assert.IsAssignableFrom<IThings>(one);
Assert.IsAssignableFrom<IThings>(two);
var actual = sut.GetCommands(builder);
Assert.Equal(1, actual.OfType<ThingOne>().Count());
Assert.Equal(1, actual.OfType<ThingTwo>().Count());
}
}
As there's no extensibility point in Moq that enables AutoFixture to hook in and supply a value of ThingOne, there's not a whole lot you can do.
However, you can use the SetReturnsDefault<T> method of Moq. Modifying the above test would then be like this:
[Theory, BasicConventions]
public void WhyCannotInstantiateProxyOfClass(
ThingOne one, ThingTwo two, IThingBuilders builder, SomeClass sut)
{
Assert.IsAssignableFrom<IThings>(one);
Assert.IsAssignableFrom<IThings>(two);
Mock.Get(builder).SetReturnsDefault(one); // Add this to make the test pass
var actual = sut.GetCommands(builder);
Assert.Equal(1, actual.OfType<ThingOne>().Count());
Assert.Equal(1, actual.OfType<ThingTwo>().Count());
}
This is a bit easier than having to write a specific Setup/Returns pair, but not much. You could move that code to an AutoFixture Customization, but again, since this is a generic method on a a Mock instance, you'll explicitly need to call this for e.g. ThingOne in order to set the default for that return type. Not particularly flexible.

Verifying indirectly called methods with Moq on a mocked object

My app has a ProviderFactory static class that has static utility methods passing back static instances of things like a logger. The rest of my app then can just grab a/the reference to the logger from anywhere without having to pass in the logger (common design practice).
So, another part of my app, the DbCacheProvider, has methods that make calls to the logger so internally it gets a reference to the logger from the factory and then issues calls to it.
My question is that using Moq, I want to verify methods on the logger are being called by the methods within the DbCacheProvider. I can do this using dependency injection when I pass a mock logger into the DbCacheProvider as a parameter, but I'm not passing the logger in (not do I want to). So, how would I verify the DbCacheProvider is making calls to the logger?
If you don't want to pass the logger in through the constructor you'd need to change your ProviderFactory while running unit tests to return your mocked logger.
Anyway there are a couple of reasons it's often suggested to set up dependency injection:
Your tests are more straightforward and don't involve finagling with custom factories
IoC frameworks like Unity, Ninject and Autofac make it easy to create objects when their dependencies are set up this way. If you set up all of your objects this way, the framework will do all the heavy lifting of creating the right objects and passing them in for you. The dependency injection is done automatically and won't be a burden for you.
Old question without an answer, I had a similar problem and solved it like this:
I have the following sample code and need to verify that not only was a method called but was called with a specific value.
public interface ILog
{
void Info(string message);
}
public interface ILogFactory
{
ILog GetLogger();
}
This is the class being tested, where the interface items are being injected:
public class NewAction
{
readonly ILogFactory _logger;
public NewAction(ILogFactory logger)
{
_logger = logger;
}
public void Step1()
{
_logger.GetLogger().Info("Step 1");
}
public void Step2()
{
_logger.GetLogger().Info("Step 2");
}
}
This is obviously a very simplistic view of my actual code, but I needed to verify that Step1 and Step2 are behaving as expected and passed the correct values to the Log, this would mean I also needed to ensure they occurred in the right order. My test:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
// Arrange
var log = new Mock<ILog>();
var factory = new Mock<ILogFactory>();
factory.Setup(l => l.GetLogger()).Returns(log.Object);
// Act
var action = new NewAction(factory.Object);
action.Step1();
action.Step2();
// Assert
factory.Verify(l => l.GetLogger());
log.Verify(l => l.Info(It.Is<string>(s => s == "Step 1")));
log.Verify(l => l.Info(It.Is<string>(s => s == "Step 2")));
}
}
Hope this helps.

PHPUnit::How can be __construct with protected variables tested?

PhpUnit::How can be __construct with protected variables tested?
(not always we should add public method getVal()- soo without add method that return protected variable value)
Example:
class Example{
protected $_val=null;
function __construct($val){
$this->_val=md5 ($val);
}
}
Edit:
also exist problem to test in function that return void
Edit2:
Example why we need test __construct:
class Example{
protected $_val=null;
//user write _constract instead __construct
function _constract($val){
$this->_val=md5 ($val);
}
function getLen($value){
return strlen($value);
}
}
class ExampleTest extends PHPUnit_Framework_TestCase{
test_getLen(){
$ob=new Example();//call to __construct and not to _constract
$this->assertEquals( $ob->getLen('1234'), 4);
}
}
test run ok, but Example class "constructor" wasn't created!
Thanks
The main goal of unit testing is to test interface By default, you should test only public methods and their behaviour. If it's ok, then your class is OK for external using. But sometimes you need to test protected/private members - then you can use Reflection and setAccessible() method
Create a derived class that exposes the value that you want to test.

Resources