4 Structuring Tests With Suites - essenius/FitNesseFitSharpGameManagementDemo GitHub Wiki
After seeing the previous result, you will probably agree that our test page is getting quite long already. It is good practice to try and make test cases relatively short and independent. However, that tends to translate into duplication of initialization code etc., which is obviously not such a good practice.
Creating a suite
That is why FitNesse has the concept of Test Suites, i.e., a set of related test pages. You set this up by making a parent page and putting the test pages under this.
In the browser, enter http://localhost:8080/GameManagementSuite. You will get a creation page. Accept the defaults and save.
Now go back to the GameManagementTest
page and move it under the suite. Click Tools – Move
Then enter New Location GameManagementSuite
, and click the Move Page
button.
The page has now moved to http://localhost:8080/GameManagementSuite.GameManagementTest. Go back to the suite page http://localhost:8080/GameManagementSuite. You will see a link to the Game Management page under the Contents header.
FitNesse shows the pages under the suite (that’s what the default content does), and you see a Suite
link instead of a Test
link in the top bar. FitNesse guessed this is a suite page because it ends with Suite
. If you used a different name, you could mark the page as Suite
on the Properties
page. What that Suite link does is running all tests on all pages below this suite page. Click it to see what happens:
Initializing Tests with the SetUp Page
For this suite, we want to setup the system under test once, and run several tests from the same base data. We do not want to duplicate that for each test in the suite. FitNesse supports that via a special page called SetUp
, which is executed before every test in a suite. Go to http://localhost:8080/GameManagementSuite.SetUp and put in the following content:
|Script|player management driver |
|ensure|add player|Steve|with skill|beginner |
|ensure|add player|Julie|with skill|intermediate|
|ensure|add player|Bill |with skill|intermediate|
|ensure|add player|John |with skill|advanced |
Save the page. Since we now extracted the buildup of our test data, we remove them from the GameManagementTest
page. The first script table then becomes:
|Script |player management driver |
|note |check if duplicates are rejected |
|$players=|player count |
|reject |add player |John |with skill |intermediate |
|check |player count |$players |
|check |player |John |if skill |advanced |
|check |player |Steve |if skill |beginner |
|note |Check that non-existing players are handled OK |
|check |player |Bart |if skill |null |
|note |make sure that all still works after the duplicate|
|ensure |add player |Tina |with skill |advanced |
|check |player count |>$players |
Rerun the suite. You will now see there is an included page called GameManagementSuite.Setup
. The tests should still pass, and although some of the assertions are now in the included page instead of the main page, they are still counted in the summary bar:
Isolating Tests
Now we can split the different tests without duplicating content. Let’s first create a test case to check for handling duplicate players. Create a new page DuplicateTest
under GameManagementSuite
: Go to http://localhost:8080/GameManagementSuite.DuplicateTest and replace the default content by:
Attempting to register an already existing user should fail. Player count should remain the same, and skill levels should not be changed.
|Script |player management driver |
|$players=|player count |
|reject |add player |John |with skill |intermediate |
|check |player count |$players |
|check |player |John |if skill |advanced |
|note |Make sure that all still works after the duplicate|
|ensure |add player |Tina |with skill |advanced |
|check |player count |>$players |
Run the test, and verify that the tests pass:
Notice that the SetUp
page is still called, even though we ran this as a test, not as a suite. This allows us to run the test by itself without having to change it.
Remove the corresponding lines from the GameManagementTest
page to make sure we’re not executing tests multiple times. Don’t forget to remove the line with player Tina in the query for advanced skills, since that player is no longer set in this test. We’re also changing the remove test to remove Steve instead of Tina for the same reason. The final content should become:
|Script|player management driver |
|note |Check that non-existing players are handled OK|
|check |player |Bart |if skill |null |
|Query: players with skill|intermediate|
|Player |
|Julie |
|Bill |
|Script |player management driver |
|$players=|player count |
|ensure |remove player |Steve |
|check |player count |<$players |
|ensure |update skill for player|Julie|to|advanced|
|Query: players with skill|advanced|
|Player |
|John |
|Julie |
Now let’s go to the Suite page and execute the full suite.
If you inspect the details, you will see that the setup lines fail in the second test. The singleton we use survives between test pages in the suite, so we need to make sure each test starts with a clean slate. There are two ways of doing that: make sure that it is explicitly cleared beforehand, or afterwards.
Cleaning Up with the TearDown Page
Let’s take the second approach since it allows us to show the TearDown
page. Go to http://localhost:8080/GameManagementSuite.TearDown, and enter the following content:
|Script|player management driver|
|ensure|clear players |
Of course, we now need to create a ClearPlayers()
method in the PlayerManagementDriver
fixture class. The return value becomes true when the clearing was successful (i.e. no players left):
public static bool ClearPlayers()
{
StaticGame.Players.Clear();
return (PlayerCount() == 0);
}
After building and running the suite again, all tests will pass.
The tests are already a lot less interdependent. Especially if the tests are more resource intensive, it makes sense to break them up into smaller pieces that can be run independently, without losing the option to run them all together.
The SuiteSetUp and SuiteTearDown Pages
There are two additional special pages that we won’t show examples for, but which work similarly: SuiteSetUp
and SuiteTearDown
. You put them directly under the suite page, like the SetUp
and TearDown
pages. The SuiteSetUp
page will be executed once, before any of the test pages run; and the SuiteTearDown
page will be executed once after all test pages finished. This allows you to prepare and clean up infrastructure matters or other things that take long to setup and can be re-used across test cases. For example, when doing web interface testing, you could very well put opening the browser in a SuiteSetUp
page, and closing it down in SuiteTearDown
, and have several test pages use the same browser session. That would be much faster than having each test page setup and teardown their own browser instance.
The processing order for a suite with two pages TestPage1 and TestPage2 is:
SuiteSetUp
SetUp
TestPage1
TearDown
SetUp
TestPage2
TearDown
SuiteTearDown
Another tool we can use to eliminate duplication is the Scenario Table. See 5 Avoiding Duplication with Scenario Tables to learn more.