I've written a class that manages recipients on a MailChimp list, called MailChimpRecipient. It uses the MCAPI class, which is an third-party API wrapper.
http://apidocs.mailchimp.com/api/1.3/ http://apidocs.mailchimp.com/api/downloads/
I pass the MCAPI object into the constructor of the MailChimpRecipient object, so I have written unit tests using PHPUnit that test all of the logic in my own class (I am not testing the MCAPI class). I have 100% code coverage and all tests pass. This is done by mocking and stubbing the MCAPI object.
My next step was to write an integration test, also using PHPUnit, where I would construct the MailChimpRecipient fixture using a real MCAPI object, set up to use a real MailChimp list.
I have written what I think is an intergration test, which basically runs tests agains the public interface of the object, like:
public function testAddedRecipientCanBeFound()
{
$emailAddress = 'fred@fredsdomain.com';
$forename = 'Fred';
$surname = 'Smith';
// First, delete the email address if it is already on the list
$oldRecipient = $this->createRecipient();
if($oldRecipient->find($emailAddress))
{
$oldRecipient->delete();
}
unset($oldRecipient);
// Add the recipient using the test data
$newRecipient = $this->createRecipient();
$newRecipient->setForename($forename);
$newRecipient->setSurname($surname);
$newRecipient->setEmailAddress($emailAddress);
$newRecipient->add();
unset($newRecipient);
// Assert that the recipient can be found using the same email address
$this->assertTrue($this->_recipient->find($emailAddress));
}
The "integration" test doesn't test any of the internals of the class - it just makes sure that given a real MCAPI object, it behaves as advertised.
Is this correct? Is this the best way to run an intergation test? After all, the internals have been tested with a unit test. Am I right in thinking that the integration test is there to test that it really works, according the way its behaviour is advertised?
To take it a step further, the MailChimpRecipient class implements an interface, which will also be implemented by other classes. The idea is to use a factory to pass different types of mailing list recipient objects to my code, which all do the same thing, albeit using different mailing list providers. Since my integration tests test the that interface, how about using it for all of the classes that implement the interface? Then, in the future, if I design a new class to be used interchangably, I can run the same integration test before inserting it into a project.
Does this sound reasonable? The unit tests test the internals of an object, intergration tests make sure that it behaves as advertised?
setUp
function to establish the grounds to run your tests. If the input is undefined, well you can't really test. The input needs to be precise, strict and always the same. If a precondition of a test is not met, skip the test instead. Then analyze why it skips and if you need to add additional tests and/or thesetUp
is not done right.DataProvider
(that's a function offering input as parameters to a test).