Integration Test: Controllers
These exercises cover tests on a controller level, that test a whole request/response cycle. They simulate a request and inspect the response and/or side effects.
- use the base controller test case
- use annotations for application state
- use data fixtures
- test ACL for backend controllers
Clone https://github.com/tddwizard/magento2-exercise-contact.git into app/code/TddWizard/ExerciseContact
. It contains a module skeleton with one custom model Inquiry
. We will write a custom contact form that saves the input in the inquiry
table.
First, we need to display the form.
Write a custom controller TddWizard\ExerciseContact\Controller\Form\Index
. Start with a test case that extends Magento\TestFramework\TestCase\AbstractController
and use dispatch()
to call your controller (exercise_contact/form
). Write at least one assertion to test if a form is displayed with exercise_contact/form/save
as action. The form should contain a text input email
and a text area message
.
For simple checks where you control the format of the HTML output, regular expressions can be sufficient. But it pays off to use a DOM parser and write custom assertions. Here are some that come in handy and could be put into an abstract base test case or a trait:
protected function assertDomElementContains(string $xpath, string $expectedString, string $message = '')
{
$dom = $this->getResponseDom();
$this->assertContains($expectedString, $dom->saveHTML((new \DOMXPath($dom))->query($xpath)->item(0)), $message);
}
protected function assertDomElementPresent(string $xpath, string $message = '')
{
$this->assertDomElementCount($xpath, 1, $message);
}
protected function assertDomElementCount(string $xpath, int $expectedCount, string $message = '')
{
$dom = $this->getResponseDom();
$this->assertEquals($expectedCount, (new \DOMXPath($dom))->query($xpath)->length, $message);
}
private function getResponseDom(): \DOMDocument
{
$dom = new \DOMDocument();
\libxml_use_internal_errors(true);
$dom->loadHTML($this->getResponse()->getBody());
\libxml_use_internal_errors(false);
return $dom;
}
You can also use this package to make assertions based on CSS selectors: phpunit/phpunit-dom-assertions
Check out solution-integration-test-1
to see a solution.
Now write the controller that handles the form, TddWizard\ExerciseContact\Controller\Form\Save
.
- Start by testing that the response is a redirect back to the form.
- Then test if a success message "We received your inquiry and will contact you shortly" is saved in the session.
- Also write tests for invalid input (empty message body, invalid email address) and test for appropiate error messages instead of the success message.
- Optional: save form data in session if there was an error and remove saved form data on success. Also test that the form is prefilled if there is saved data.
Take a look at the assert...
methods from the AbstractController
test base class, they will be useful.
Do not actually save anything yet, that's part of the next exercise.
Check out solution-integration-test-2
to see a solution.
Now it's time to save the posted data. Add assertions to the tests from the previous exercise for:
- a new inquiry is saved with the posted data
- nothing is saved if the posted data was invalid
Use the InquiryRepositoryInterface
to inspect the database. Try out, how the @magentoDbIsolation enabled
annotation affects the test database. Tipp: Truncate inquiry table in setUp
method.
Check out solution-integration-test-3
to see a solution.
For logged in customers, the email address field should not be displayed, and the saved email address should come from the customer account.
Extend your tests for this new case.
Use @magentoDataFixture
with one of the fixtures of the core test suite to create a test customer. Use the customer session to set the test customer as logged in.
Check out solution-integration-test-4
to see a solution.
The module already contains generated code for an admin grid. Let's write a simple test case to verify that the grid loads and shows saved inquiries.
Write a new test case that extends Magento\TestFramework\TestCase\AbstractBackendController
. This base class takes care of authentication for the admin user.
Use the InquiryRepository
to save a new inquiry before dispatching the grid controller.
You will notice that the test case already contains two tests which are marked as incomplete by default:
- AclHasAccess test is not complete
- Acl test is not complete
Provide values for the $uri
and $resource
attributes to automatically test access control.
Check out solution-integration-test-5
to see a solution.
- Hire me to come to your company: https://www.integer-net.com/services/magento-training-courses/#M2-test
- Subscribe to the Test Driven Magento newsletter to get notified about other possibilities: http://tddwizard.com/