Using Test Controllers for Testing

This post is part of the Pride & Paradev series.


A test controller is a way to directly access functionality in your web application without following the standard web application flow: for example, you may want to directly access the credit card details screen, so what you do is develop a ‘credit card details controller’ which sets the desired state (an order and a customer) and shows the credit card details screen to you.

The test controller is hit via a test URL which sets the state and redirects to the appropriate page. These test controllers are either not deployed to production, or are disallowed via routing in production.

So, should you use test controllers for testing?


You should use test controllers for testing

Test controllers make for very efficient and easy to read automated acceptance tests. Instead of something like:

Given I am on the home page
When I add some products to my basket
And I provide my customer details
And I select express shipping
Then I should see the customer details screen
When I submit an invalid credit card number
Then I should see an error
And the credit card details are empty and need to be reentered

This can simply become:

Given I am on the credit card details page
When I submit an invalid credit card number
Then I should see an error
And the credit card details are empty and need to be reentered

The Given step simply calls the test controller that sets up required state and provides the screen. The scenario is focused on testing one thing and isn’t reliant on a process flow to set up the state.

Test Controllers also allow you to test something before other things are developed. For example, in the above case you could test the credit card details screen even though the shipping selection page was not developed. As long as the controller sets things up correctly, it allows you to test stories in isolation without having dependencies on other user stories, which results in faster velocity.

You shouldn’t use test controllers for testing

Test Controllers set up state in your web application, which may be different to the state set up by using the application itself. For example, a test controller for credit card details may set the shipping method, but it may set it differently to how the shipping method screen does it, which results in inconsistent behavior in your application, and potentially false positives. This leads to failures where you are not sure whether there is an bug in your application, or just in the test controller itself.

User’s don’t use test controllers so neither should you. It may be convenient to jump into testing a certain page but testing is as much about the journey as the destination, so jumping straight in may mean you miss important bugs along the way.

5 thoughts on “Using Test Controllers for Testing

  1. I achieve this by using hooks in SpecFlow.

    @CreditCardEntry
    Scenario: The user pays using Mastercard.
    Steps etc etc etc

    Then I have a hook which gets me to the position to start this scenario.

    [BeforeFeature("CreditCardEntry")]
    public static void NavigateToPaymentPage()

    This would then complete the tasks I need, but I don’t have to repeat the steps for each scenario I have on that feature.

    1. Yes, I understand you can use hooks, but you still have time to navigate through all pages: which may have other errors, or may not be implemented yet.
      So this is why I like test controllers for automated acceptance tests: remove all flow dependencies.
      We also have 4 end to end tests that check all pages flow together.

  2. Yes I agree, with also have a “backdoor” to login and go straight to a page, and use cookies to set certain data.Like what project to have open. But we inturn also have several end to end scenarios, which is awesome with specflow as already have the steps created.

  3. Having tests that test specific areas via the test controllers and the separate end to end tests that cover the same area (a bit or more) using normal flow should provide coverage gap or runtime length & complexity of either approach alone, though there is some duplication of coverage.

    On a related note, covering the whole flow just to test a specific area eats up runtime when done via the UI. I was wondering what others think about going through the flow but bypassing the UI for web apps by using the core HTTP/REST interface, making the same HTTP/AJAX calls that the web app does for parts of the flow we don’t specifically need to critically test. That way, you speed up the test setup & runtime using a flow that more closely matches reality (only thing not covered here is javascript & AJAX behavior & UI rendering, but the flow is roughly same as going through UI). And one reuses (session) cookies between Selenium and the HTTP calls to keep/persist through session data.

    1. I’ve had success using a strategy of using HTTP headers and bypassing the UI to get to the functionality the test is actualyl meant to test. We still make sure the proper path is tested at least once through the UI and make the trade off between faster feedback and accuracy.

      The best solution however is the parallelize as much as possible so you don’t have to make these sorts of tradeoffs.

Comments are closed.