Types of testcases in PHPUnit - php

I am new to PHPUnit, infact I started today. And, as far as I have been reading, I came to understand only what this script does.
class UserTest extends PHPUnit_Framework_TestCase
{
protected $user;
// test the talk method
protected function setUp() {
$this->user = new User();
$this->user->setName("Tom");
}
protected function tearDown() {
unset($this->user);
}
public function testTalk() {
$expected = "Hello world!";
$actual = $this->user->talk();
$this->assertEquals($expected, $actual);
}
}
For this class:
<?php
class User {
protected $name;
public function getName() {
return $this->name;
}
public function setName($name) {
$this->name = $name;
}
public function talk() {
return "Hello world!";
}
}
Ok, so I have established that the test returns a Ok/Fail statement based on the equality of the test, but what I am looking for is more. I need an actually ways to test a more complex class that, its outcome, un-like in this example can not be guessed easily.
Say, I write a script that does polling. How would, or in what ways can I test if the methods/classes can work? The above code only shows if a methods outcome will only be 'Hello World' But, that is too easy thing to test, because I need to test complex things and there aren't much tutorials for that.

Testing a class in a unit test is supposed to NOT be complex.
And the reason for this to be true is that in a well designed system, you can test that class in isolation, and do not add the complexity of the system behind that class - because that system does not exist during the test, it is mocked.
The classic example for this is that a User class usually asks a database for info, but in the test case, that database is really hard to set up, prepare with data, and destroy afterwards. And using a real database also slows things down. So you design the User class to accept a database object from the outside, and in the test case you give to it a mock object of the database.
That way, it is really simple to simulate all kinds of return values from the database, and additionally you can check whether the database object gets the right parameters without the complexity of dealing with a real database.
You can only do proper mock object injection if your classes are designed to allow dependency injection. That is a principle to NOT create objects inside of other objects, but require the outside world to supply them. Just have a quick look at some video for explanation:
Dependency Injection - Programming With Anthony (Jan 2013)
And remember that creating good tests needs some experience. Good for you to start experimenting.

But, that is too easy thing to test, because I need to test complex things and there aren't much tutorials for that.
The more complex, the more complex the tests are. It's a bit like a snake biting in its own end. You normally want to prevent that, so to make it golden: Write simple tests to ensure that a complex software is tested and runs.
This does not always work 100% but it works better than without tests. PHPUnit has been designed for Unit-Tests (Xunit test patterns) but you can also use it to run different tests. For that you group tests. This is done differently by different people depending on different things. For example:
Small tests
Medium tests
Large tests
or (not equivalent):
Unit tests
Integration tests
Acceptance tests
or (perhaps equivalent TestPyramid):
Unit tests
Service tests
UI tests
and what not. When you start with testing, it's probably good to start with the unit-tests and as Sven already answered, keep them simple. Get comfortable with TDD, read some slides and books. And welcome to the world of automating tests.
What is Unit test, Integration Test, Smoke test, Regression Test?
P.S. Yes, simple getter setters are too easy to test. If all a setter does is storing to a private member and the getter gets it back, you can trust that PHP is working, writing a test for that is a waste of time and will only lead to cruft. It clearly shows that somebody wrote the test after the code has been written. Instead write first the test and see it fail (red), than hack together the code as quick as possible to get the test to pass (green). You can improve the code later on as the test already shows it's working.

Related

When to use stubs/mocks and when to use real objects in unit testing?

I recently tried to improve my unit testing skills and read quite some literature about unit testing and I am also trying to realize what I learned in a php-project I am currently developing with phpunit. But I still have a in my opinion very fundamental question how to unit test methods which interact with objects of other classes or even with other methods of the same class.
Is there some rule of thumb or some help how I can decide what dependencies I should stub/mock and for what dependencies I should simply use a normal object? To clarify my question, here is an example code, with different scenarios:
interface DependencyInterface {
public method dependentMethod() { ... }
}
class Dependency implements DependencyInterface {...}
class ClassUnderTest {
private $dependency
public __construct(DependencyInterface $dependency) {
$this->dependency = dependency;
}
public function methodUnderTest() {
...
$result1 = $this->dependency->dependentMethod();
...
$result2 = $this->otherMethod();
...
$result3 = $this->usedInMultiplePublicMethods();
}
public function otherMethod() {...}
private function usedInMultiplePublicMethods() {...}
}
So my questions are now for a unit test which tests the functionality of the method methodUnderTest, should I:
stub the interface DependencyInterface and inject it in the constructor, or should I simply use an instance of the implementation Dependency?
partially stub the class ClassUnderTest itself to deliver a fixed result for otherMethod, since this maybe very complex method has already its own complete unit tests?
I decided to not unit tests private methods, since they are not part of the interface of the class (I know this is a controversial topic and is not the scope of my question). Do I have now to cover for each public method which uses the private method usedInMultiplePublicMethods all possible effects which may occur in the private method? Or should I only test all possible effects in one of the public methods which uses it and stub the private method in the tests for all other public methods?
I am quite not sure about when to use stubbing/mocking and when not.
The why of mocking is to be able to write unit test that means a test which is: fast, isolated, repeatable, self validating and Thorough and Timely (F.I.R.S.T)
To be able to test a unit/module in isolation you may need to mock/stub any external module (database access, api call, logging system...).
For your points 1 & 2 , rad's answer points to main underlying principles to keep in mind e.g. if you are going to test a logic which is using a database service to fetch data and then doing computations on fetched data, would you mock that database service or use real database service ?
As is clear from objective - you are unit testing logic itself and not database service data fetch so you would mock database service and would assume that database service is giving correct data & you would simply focus on testing logic on computed data. You will have separate tests for database fetching service and that isolation property is all about.
The word unit is significant in that sense that your these tests should be very focused on current logic only by limiting your scope & by not cluttering everything else into it.
This answer is mainly for your points # 3. Its OK to not explicitly test private methods but if you go by basic purpose of unit tests - you wouldn't be much worried about something being private or public. Somewhere down the line, unit testing is for developer self satisfaction too & it would simply make your code more robust if unit tests are written for private methods too.
Just because access level is private doesn't change the basic concept that its a piece of logic that needs testing. Code coverage wise , you might be OK from one public method but I am of view that you should treat calls from different public methods as distinct.
Never forget the basic purpose of unit tests - that you are trying to find errors in your logic, trying to cover all boundary cases & trying to make your code more robust.

Correct unit testing

I started using unit and functionality test with this project and because of this I have some questions:
Im working with the symfony php framework. And I have a doctrine like LDAP ORM service.
Furthermore I have a user repository (as a service) which depends on the LDAP ORM service, the logger and a validation service.
Now I want to write a unit test for the addUser function of the UserRepo.
It will internally call: getNewUidNumber, userToEntities, doesUserExist and getUserByUid.
My question is:
Should I mock all these internal function to just test the addUser function? Would that be against the unit test idea (just test the API).
Or should I just mock the LDAP ORM service, the Logger, and the validation service, so that the class calls all internal functions? But this would cause a huge test function with a lot of mocking because I have to mock the repositories for all internal repositories calls.
Or should I start the symfony kernel and use the ServiceContainer to use the ORM LDAP service with a real test database. But wouldn't that be a functionally test and not a unit test?
I heard that its bad to have so many dependencies in a test. So I thought it would be bad to use the whole serviceContainer.
Adduser:
public function addUser(User $user)
{
$pbnlAccount = $this->userToEntities($user);
if(!$this->doesUserExist($user)) {
$pbnlAccount->setUidNumber($this->getNewUidNumber());
$this->ldapEntityManager->persist($pbnlAccount);
$this->ldapEntityManager->flush();
}
else {
throw new UserAlreadyExistException("The user ".$user->getUid()." already exists.");
}
return $this->getUserByUid($user->getUid());
}
For more code, like the internal functions:
https://gist.github.com/NKPmedia/4a6ee55b6bb96e8af409debd98950678
Thanks
Paul
First, I would like to rewrite the method a tiny bit, if I may.
public function addUser(User $user)
{
if ($this->doesUserExist($user)) {
throw new UserAlreadyExistException("The user ".$user->getUid()." already exists.");
}
// ... shortened for brevity
$pbnlAccount = $this->userToEntities($user);
$this->ldapEntityManager->persist($pbnlAccount);
}
The other relevant method is:
private function doesUserExist(User $user)
{
$users = $this->ldapRepository->findByUid($user->getUid());
return count($users) === 1;
}
Immediately we can see that we basically have two tests:
We test that the method throws when the user exists
We test that the method persists a PbnlAccount if the user does not exist.
If you do not see why we have these two tests, note that there are 2 possible "flows" in this method: one where the block inside the if statement is executed, and one where it is not executed.
Lets tackle the first one:
public function testAddUserThrowsWhenUserExistsAlready()
{
$user = new User();
$user->setUid('123');
$ldapRepositoryMock = $this->createMock(LdapRepository::class);
$ldapRepositoryMock
->method('findByUid')
->expects($this->once())
->with('123')
->willReturn(new PbnlAccount());
$userRepository = new UserRepository($ldapRepositoryMock);
$this->expectException(UserAlreadyExistException::class);
$userRepository->addUser($user);
}
The second test is left as an exercise for the reader :)
Yes you will have to do some mocking in your case. You wil need to mock the LdapRepository and LdapEntityManager both in this case.
Note 1: this code probably is not runnable, since I do not know the exact details of your code base (and I wrote this off the top of my head), but that is beside the point. The point is that you want to test for the exception.
Note 2:
I would rename your function to createNewPbnlAccountForUser(User $user) which is longer, but more descriptive of what it actually does.
Note 3:
I am not sure why you are returning $this->getUserByUid() since that seems redundant (you already have the User right there), so I am ommitting that case.
You need to mock ldapEntityManager and all repository services but not the internal function.And as you said, don't boot kernel in unit test. So, you should test all cases with success and throwing exception (make sure to check all behaviour)
If you want to perform a unit test, you should mock all collaborators.
Now, entity managers, ldap services and so on should not be mocked (read more here).
Moreover, if you happen to be in a situation where the Arrange part (set mocks, stubs, and so on) is painful and take "a lot" of the test, maybe this is a smell that your class has too many responsibility (is doing too much things).
That said, when I do unit test, I would like the test to fail only for an internal (to the class) reason, not because I've changed a collaborator line that messes up all my tests.

Function Structure vs Unit Testing Private Function

I have a function, which someone else wrote, that creates a cURL wrapper object inside the function. Simplified version below
public function getCodes()
{
//do some stufff
$communicator = new Communicator();
$result = $communicator->call($this->API_KEY);
//do some stuff with $result
}
I was tasked with learning PHPUnit and writing tests for this type of code. In doing so I found that it's really hard to test a function like this when the object is created inside of the function and also that tests shouldn't require any outside communication to work.
We wanted to push our tests to git as many projects do but we didn't want to accidentally or intentionally push our API credentials to git.
So my solution was to keep getCodes() public but make it a wrapper for a private function that accepts a Communicator object as a parameter. Then I could test the private method with a mock Communicator object.
But this would mean that getCodes is never tested (my boss wants 100% code coverage) and I also read that you shouldn't be writing tests for private functions in most circumstances.
So my question is basically, how do I write a test for a function like this with an API call.
I would really suggest rewriting the code to inject the Communicator object via constructor.
If you already see there is a big issue with writing tests for something it is a very strong signal to re-thing the current implementation.
Another thing is that you shouldn't test your privates. Sebastian Bergmann wrote a post on his blog about this some time ago and the conclusion is - it is possible just not good (https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html).
Completely different thing is that I think your tests shouldn't go outside of the boundaries of your system. That is - mock everything that connects to outside systems. Such tests may fail for various of reasons non of witch are valid from the sole perspective of running tests.
You also mentioned coverage. Unfortunately this is something where, I hope, everyone will agree - you cannot have it the moment you start using native PHP resources (with some small exception like FS). You have to understand that things like curl, ssh, ftp and so on cannot be unit tested.

Am I setting myself up for failure using a static method in a Laravel Controller?

I am quite new to OOP, so this is really a basic OOP question, in the context of a Laravel Controller.
I'm attempting to create a notification system system that creates Notification objects when certain other objects are created, edited, deleted, etc. So, for example, if a User is edited, then I want to generate a Notification regarding this edit. Following this example, I've created UserObserver that calls NotificationController::store() when a User is saved.
class UserObserver extends BaseObserver
{
public function saved($user)
{
$data = [
// omitted from example
];
NotificationController::store($data);
}
}
In order to make this work, I had to make NotificationController::store() static.
class NotificationController extends \BaseController {
public static function store($data)
{
// validation omitted from example
$notification = Notification::create($data);
}
I'm only vaguely familiar with what static means, so there's more than likely something inherently wrong with what I'm doing here, but this seems to get the job done, more or less. However, everything that I've read indicates that static functions are generally bad practice. Is what I'm doing here "wrong," per say? How could I do this better?
I will have several other Observer classes that will need to call this same NotificationController::store(), and I want NotificationController::store() to handle any validation of $data.
I am just starting to learn about unit testing. Would what I've done here make anything difficult with regard to testing?
I've written about statics extensively here: How Not To Kill Your Testability Using Statics. The gist of it as applies to your case is as follows:
Static function calls couple code. It is not possible to substitute static function calls with anything else or to skip those calls, for whatever reason. NotificationController::store() is essentially in the same class of things as substr(). Now, you probably wouldn't want to substitute a call to substr by anything else; but there are a ton of reasons why you may want to substitute NotificationController, now or later.
Unit testing is just one very obvious use case where substitution is very desirable. If you want to test the UserObserver::saved function just by itself, because it contains a complex algorithm which you need to test with all possible inputs to ensure it's working correctly, you cannot decouple that algorithm from the call to NotificationController::store(). And that function in turn probably calls some Model::save() method, which in turn wants to talk to a database. You'd need to set up this whole environment which all this other unrelated code requires (and which may or may not contain bugs of its own), that it essentially is impossible to simply test this one function by itself.
If your code looked more like this:
class UserObserver extends BaseObserver
{
public function saved($user)
{
$data = [
// omitted from example
];
$this->NotificationController->store($data);
}
}
Well, $this->NotificationController is obviously a variable which can be substituted at some point. Most typically this object would be injected at the time you instantiate the class:
new UserObserver($notificationController)
You could simply inject a mock object which allows any methods to be called, but which simply does nothing. Then you could test UserObserver::saved() in isolation and ensure it's actually bug free.
In general, using dependency injected code makes your application more flexible and allows you to take it apart. This is necessary for unit testing, but will also come in handy later in scenarios you can't even imagine right now, but will be stumped by half a year from now as you need to restructure and refactor your application for some new feature you want to implement.
Caveat: I have never written a single line of Laravel code, but as I understand it, it does support some form of dependency injection. If that's actually really the case, you should definitely use that capability. Otherwise be very aware of what parts of your code you're coupling to what other parts and how this will impact your ability to take it apart and refactor later.

How to use PHPUnit to test a method that calls other methods of the same class, but returns no value

How do you write a unit test for a method that calls other methods of the same class, but doesn't return a value? (Let's say with PHPUnit.)
For example, let's say that I have the following class:
class MyClass {
public function doEverything() {
$this->doA();
$this->doB();
$this->doC();
}
public function doA() {
// do something, return nothing
}
public function doB() {
// do something, return nothing
}
public function doC() {
// do something, return nothing
}
}
How would you test doEverything()?
EDIT:
I'm asking this because from what I've read it seems like pretty much every method should have its own dedicated unit test. Of course, you also have functional and integration tests, but those target specific routines, so to speak (not on a per method level necessarily).
But if pretty much every method needs its own unit test, I'm thinking it would be "best practice" to unit test all of the above methods. Yes/no?
Okay! I've figured it out! As might be expected, mocking is what I need in this situation--and mocking a sibling method is called partial mocking. There's some pretty great info about PHPUnit mocking in this article by Juan Treminio.
So to test doEverything() in the above class, I would need to do something like this:
public function testDoEverything()
{
// Any methods not specified in setMethods will execute perfectly normally,
// and any methods that ARE specified return null (or whatever you specify)
$mock = $this->getMockBuilder('\MyClass')
->setMethods(array('doA', 'doB', 'doC'))
->getMock();
// doA() should be called once
$mock->expects($this->once())
->method('doA');
// doB() should be called once
$mock->expects($this->once())
->method('doB');
// doC() should be called once
$mock->expects($this->once())
->method('doC');
// Call doEverything and see if it calls the functions like our
// above written expectations specify
$mock->doEverything();
}
That's it! Pretty easy!
BONUS: If you use Laravel and Codeception...
I'm using the Laravel Framework as well as Codeception, which made it a little bit trickier to figure out. If you use Laravel and Codeception you'll need to do a little bit more to get it working, since the Laravel autoloading doesn't by default connect into the PHPUnit tests. You'll basically need to update your unit.suite.yml to include Laravel4, as shown below:
# Codeception Test Suite Configuration
# suite for unit (internal) tests.
class_name: UnitTester
modules:
enabled: [Asserts, UnitHelper, Laravel4]
Once you've updated your file, don't forget to call php codecept.phar build to update your configuration.
While your mocking test does achieve your goal, I would argue that you've decreased confidence in the code. Compare the original trivial method to the complicated method that tests it. The only way the method under test can fail is by forgetting to add one of the method calls or mistype a name. But you're now doubly-likely to do that with all that additional code, and it doesn't have any tests!
Rule: If your test code is more complicated than the code under test, it needs its own tests.
Given the above, you're better off finding another way to test the original code. For the method as written--three method calls with no parameters--inspection by eyeball is sufficient. But I suspect that the method does have some side-effects somewhere, otherwise you could delete it.
Unit testing is about testing the class as a unit, not each method individually. Testing each method alone is a good indication that you're writing your tests after the code. Employing Test Driven Development and writing your tests first will help you design a better class that is more-easily testable.

Categories