What is the sense of a mock object in PHPUnit? - php

I'm developing a intern app which send some emails in a view methods. Now I'm rebuilding this app TDD-style but I'm stuck at some point. I searched the web for how to test emails with PHPUnit and the solution was, use mock objects. I read some articles and tutorials about it and built a test with a mock object.
The test passed but I don't understand why should use a mock object if you already know the result. I mean, if you already know the result you don't see the failure on your real method? So is this not the way to test methods which use the email function or am I just doing it wrong? Probably the second one haha.
Thanks in advance,
Sjors

When you are unit testing you should be trying to test your method under test (unit of work under test) in isolation from the rest of your system. As soon as you are forced to cross a system boundary, your unit test becomes an integration test. Integration tests tend to be more fragile, harder write and harder to maintain. By isolating the mailing component from the method that creates the mail you no longer need to rely on whether the mailing system is up and running when you unit test runs. You are free to test the logic in the method under test without having to depend on a concrete implementation.
There are two categories of mock tests, interaction tests and state based tests. I'd suggest looking up the difference between the two on google.
I am unfortunately not familiar with the syntax of php to I can only show you an example of what you might be testing in your case using C# syntax, but I am sure you will be able to follow the code.
public interface Mailer
{
void Send(string to, string from, string subject, string body)
}
The above interface would be one that matches the signature of your mailing component that actually sends the mail (it knows about smtp etc).
public class MailSender
{
private IMailer _mailer;
public MailSender(IMailer mailer)
{
_mailer = mailer;
}
public void GenerateMail(string to, string cc, string from, string subject, string body)
{
if (IsValidEmailAddress(to) == false) throw new InvalidEmailAddressException("To");
if (IsEmptySubject(from) == false) throw new EmptySubjectException();
_mailer.Send(to, from, subject, body);
}
private bool IsValidEmailAddress(string emailAddress)
{
// some code/regex to check that the email address is valid
}
private boold IsEmptySubject(string subject)
{
// code to check if the subject is empty
}
}
Now we have logic in the GenerateMail method. You can write unit tests to check if you get exceptions for invalid email addresses and an empty subject and you can also write a unit test to ensure that if you have valid email addresses and a subject that is not empty the send method is called on the mocked mail sender with the correct information in each of the parameters. This type of unit test would an interaction test as the mock is just verifying that the method was called).
Hope this explanation helps.

The reason to use mock objects is isolation. If you write unit tests you want them to be as isolated from other systems or code as possible. Hence the name unit tests. Using mocks allows you to isolate your tests from other systems (email in your case). There is a talk by Misko Hevery http://www.youtube.com/watch?v=acjvKJiOvXw that explains this aspect better than I ever could.

Related

I can't figure out how to PHPUnit test Ratchet/Sockets

Let me first confess that I absolutely am a novice in the field of TDD and unit tests. Currently, I am learning to work with TDD to advance myself in my career.
I am reprogramming a program I wrote a year ago using TDD. The program is not that complex. It listens to a websocket (Ratchet), receives information, parses the information, and sends messages through a message bus (RabbitMQ).
I am trying to approach this via TDD so I am starting to write my test first.
My listener class has 4 methods.
Connect (connects to the stream via Ratchet)
Listen (starts listening)
Parse (parses received information)
SendMessage (send a message to the RabbitMQ bus)
The problems I encounter while writing the test first.
How can I mock a Ratchet connection and assert that my function can "connect"
How can I assert that the information received matches my expectations
I find it really hard to find information on this specific subject and I understand that my question is broad. I do not expect a complete solution or answer but hopefully, the terminology to further investigate this subject and lectures/tutorials about writing tests for methods of this kind.
It's hard to argue without having seen any code. From your description it sounds like you have one class that does all the things. This may already be a reason that makes testing harder than it has to be.
When it comes to unit tests, I like to stick with Michael Feathers definition:
A test is not a unit test if:
it talks to the database.
it communicates across the network.
it touches the file system.
it can't run at the same time as any of your other unit tests.
you have to do special things to your environment (such as editing config files) to run it.
Mocking the Ratchet and RabbitMQ connections may seem like a way to make a test fit the above definition, but there is also this other phrase: "Don't mock what you don't own". Although it's not a hard rule, I think it's a pretty good guideline. There are a lot of articles on that topic. This should give you a good overview
Ratchet is a bit special with the server and event loop part, though. But it's well tested, so you don't have to do it. My suggestion: Keep the integration with Ratchet so thin, that there isn't much left to test anyway and just skip the test.
final class MyRatchetApp implements MessageComponentInterface
{
private MessageProcessor $processor;
public function __construct(MessageProcessor $processor)
{
$this->processor = $processor;
}
public function onMessage(ConnectionInterface $from, $msg)
{
$this->processor->handle($msg);
}
// ...
}
This leaves you with a MessageProcessor that you can test in isolation. All of its dependencies are types you own, so you can use mocks, stubs or fake implementations to test their interaction. This implementation is overly simplified and misses stuff like error handling that you certainly want to do and of course want to test.
final class MessageProcessor
{
private MessageParser $parser;
private MessageBroadcaster $broadcaster;
public function __construct(MessageParser $parser, MessageBroadcaster $broadcaster)
{
$this->parser = $parser;
$this->broadcaster = $broadcaster;
}
public function handle(string $rawMessage): void
{
$this->broadcaster->send($this->parser->parse($rawMessage));
}
}
interface MessageParser
{
/**
* #throws BadMessageException
*/
public function parse(string $message): Message;
}
interface MessageBroadcaster
{
/**
* #throws UnsupportedMessageException
* #throws UnroutableMessageException
*/
public function send(Message $message): void;
}
Creating an implementation of the MessageParser should be straightforward and easily unit testable. The RabbitMQ implementation of the MessageBroadcaster would be a perfect candidate for an integration test.
Finally, plug all the concrete implementations together for the real application.
$server = IoServer::factory(
new MyRatchetApp(
new MessageProcessor(
new CommandMessageParser(),
new RabbitMqMessageBroadcaster()
)
),
8080
);
To make sure all parts work together, you can create some end-to-end tests that perform full roundtrips and verify the results. Creating these tests first, allows you to do Double Loop TDD

PHPUnit: how to test commands or functions that modify state?

Trying to get into Unit Testing. Since I'm also implementing CQRS, I was wondering how I would test something like this:
class CommandHandler{
private $repository;
public function __construct( $repository ){
$this->repository = $repository;
}
public function handle( $command ) {
$Entity = new Entity( $command->getSomething() );
$this->repository->add( $Entity );
}
}
Taken that Unit Testing is about testing the public API of my classes, what exactly would I want to test here? That an instance of Entity is passed to the repository?
Trying to get into Unit Testing. Since I'm also implementing CQRS, I was wondering how I would test something like this
The two presentations you want to watch:
Katrina Owen: 467 Tests, 0 Failures, 0 Confidence
Sandi Metz: Magic Tricks of Testing
The TL;DR of both talks is: .
Query messages and command messages sent to the subject of the test are asserted by querying the state of the test subject. Command messages sent by the test subject are verified by expectation -- you confirm that the correct message was sent, without worrying about the effects of that message.
So the answer to your question depends in part on whether or not, for this test, the repository is part of the system under test, or part of the boundary. If the repository is part of the system under test, then you can treat the entire test as verification of an incoming message, and query the state of the repository. If the repository is part of the boundary (if it is provided by the test), then you test the expectation -- was the method on the repository invoked correctly?
In the latter case, there is an additional interesting question: is the need to verify the expectation a code smell? It could be that the test -- by inducing a check against an expectation -- is actually revealing a problem in the design; maybe there should be more instrumentation in the command handler itself, so that the test can query the command handler itself to find out what messages have been sent. Scott Bellware's Doctrine of Useful Objects explores this idea.

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.

PHP Mockery: how to set expectation on a method OR another method?

I'm trying to use Mockery and PHPUnit to test if one method OR another method of a given class will be called when some piece of code is executed.
This is exactly what I'm trying to do (I'm using Laravel 5):
// Test an email is sent to new user
// upon account creation.
public function testEmailSentOnNewUserCreation()
{
// Mail can be sent right on ...
Mail::shouldReceive('send')->once(); //...OR...
// ... it can be queued for later.
Mail::shouldReceive('queue')->once();
// I'm ignoring parameters and returning values here
// for sake of brevity.
$u = new User;
$u->name = 'Jon Doe';
$u->email = 'jon#doe.com';
$u->save();
}
So, my question is about how to implement the OR part, if it's possible.
I also searched for some PHPUnit annotation that could be helpful, but I couldn't find anything.
One of the paradigms of unit testing is that you should be in control of the exact flow for each test case you implement. That's why no if, switch, etc should appear in your test.
Whenever the object under test behaviour depends on another object, or on a given condition (which logically is more or less the same), the dependency must be mocked in order to take control of the case you're testing.
So, in your case, you should mock the dependency that makes your class invoke the send or queue methods.
I think that's why testing frameworks do not implement what you intended to use.

Categories