In addition to the unit tests we’re already writing for each of our core classes, we should also write some integration tests to ensure our types interact properly.

Naturally, this gives rise to a simple question: How should we structure our integration tests?

Using the classic Given-When-Then structure popularized by Cucumber with the Gherkin language seems like a useful approach.

For those who haven’t seen it before, the Gherkin language breaks the test down into three parts. First, you set up the context for the test (Given), then you take an action (When), and finally, you check for the expected outcome (Then).

To illustrate, here’s how one of the WordTutor tests could be written, to verify that the transitions between screens work properly:

Scenario: When starting new vocabulary word, add vocabulary word screen opens
Given an application state with vocabulary "music pace" 
And the current screen is the "vocabulary browser screen"
When the action is "open new word screen"
Then assert the current screen is "add vocabulary word screen".

The very popular SpecFlow project is one way to write tests in this style - but I want to experiment with a different approach, one that doesn’t require plugins for Visual Studio or separate compilation steps.

Playing around with ideas for a pure C# technique, I’ve discovered that some of the features recently introduced into the language make it quite possible.

To this end, I’ve published a small experimental library on NuGet that provides a Given-When-Then syntax for defining/structuring tests.

Here’s an example of the library in use, expressing the same test as shown above.

[Fact]
public void WhenStartingNewVocabularyWord_AddVocabularyWordScreenOpens() =>
    Given(ApplicationStateWithVocabulary, MusicPace)
    .And(CurrentScreenIs, VocabularyBrowserScreen)
    .When(TheActionIs, OpenNewWordScreen())
    .Then(AssertTheCurrentScreenIs<AddVocabularyWordScreen>);

This test method starts with two lines to establish the current context for the test - with the vocabulary set “Music Pace” loaded and the browser as the current screen. After that, we apply the action “Open New Word Screen”, and lastly check that the current screen has changed to the expected one.

If you look at the associated code, you’ll see the tests are isolated in VocabularyMaintenanceInteractionTests while all the building blocks can be found in the base class InteractionTestsBase. This separation makes the tests themselves easier to read, and will (hopefully!) make it easier to add new integration tests as we go forwards.

Prior post in this series:
Restructuring Reducers
Next post in this series:
Dependency Injection: Core

Comments

blog comments powered by Disqus