9 Fixture Usage Tips And Tricks - essenius/FitNesseFitSharpGameManagementDemo GitHub Wiki

Life Span of Script Fixture Instances

Usually, every time you declare a new script table on a page, a new instance of a fixture is created, and the scope of the test gets set to that instance. Here is an example to show that. First the fixture:

namespace TestSlim
{
    public class MemoObject
    {
        public MemoObject(string data) => Data = data;
        public MemoObject() => Data = string.Empty;
        public string Data { get; set; }
        public int Id => GetHashCode();
    }
}

Our test page looks as follows:

!|script|memo object|C3PO|
|check  |data       |C3PO|
|$id=   |id              |

!|script |memo object|
|check   |data |     |
|check   |id   |!=$id|

Memo Object 1

As you can see, the id (i.e. hash code) returned for both tables is different, so we are dealing with two different fixture objects. However, if we make a subtle change in the test page, we will continue using the same instance. The change is to omit the fixture name in the second table:

!|script|memo object|C3PO|
|check  |data       |C3PO|
|$id=   |id              |

!|script        |  
|check|data|C3PO|
|check|id  |$id |

Memo Object 2

You can use this feature to split longer running test tables into smaller sections without changing context. The advantage of this is that you can group logical parts of your tests, and FitNesse will update the test page as soon as a test table is finished, so you will get quicker feedback, which is handy if your tests are not that quick (e.g. when automating tests at the UI level). Smaller test tables also usually look better because the formatting is easier to optimize.

Switching Script Fixture Contexts

The previous section on life spans already showed you can have different contexts for your scripts. If you need to be able to refer to a specific fixture, then you can do that using the Get Fixture function, which is always available for every fixture. Simply store the output of that function into a symbol, and then create a script table with that symbol as the parameter:

!|script|memo object|C3PO|
|check  |data       |C3PO|
|$id=   |id              |
|$c3po= |get fixture     |

!|script|memo object|
|check  |data |     |
|check  |id   |!=$id|

!|script|$c3po    |
|check  |data|C3PO|
|check  |id  |$id |

Get Fixture

There are also Push Fixture and Pop Fixture functions. These allow you to temporarily save a fixture instance to re-use it later. These are especially useful to have scenarios use their own context and reverting to the main context after the scenario was finished. For example:

!|scenario|R2D2 differs from|id   |
|push fixture                     |
|start    |memo object      |R2D2 |
|check    |data             |R2D2 |
|check    |id               |!=@id|
|pop fixture                      |

!|script          |memo object|C3PO|
|check            |data       |C3PO|
|$id=             |id              |
|R2D2 differs from|$id             |
|check            |data       |C3PO|
|check            |id         |$id |

Push Pop Fixture

This example also shows the use of the command Start, which allows you to start a new script fixture instance during execution of a script table, and switch to its context.

Fixture Assembly and Namespace Specification on Test Pages

This repo uses FitSharp’s concept of a suite configuration file to specify fixture assemblies and name spaces, as that is the preferred way. An alternative to that is using !path statements to specify assemblies, and Import tables for name spaces. To make that work, the COMMAND_PATTERN variable needs %p at the end:

COMMAND_PATTERN=%m ${FITSHARP_HOME}\\Runner.dll -c ${FIXTURE_FOLDER}\\config.xml %p

This makes FitSharp require an explicit !path specification. It must be there (can be an empty string), or it won’t run any tests. If you use this mechanism, you will not require the ApplicationUnderTest section in the configuration file config.xml. You will still need the Settings section. You can still also use the suite configuration file for additional assemblies.

So let's take the section:

  <ApplicationUnderTest>
    <AddAssembly>GameManagementFixtures.dll</AddAssembly>
    <AddNamespace>GameManagementFixtures</AddNamespace>
  </ApplicationUnderTest>

You could delete that section, and replace it on a test page by:

!path "GameManagementFixtures.dll"

!|Import               |
|GameManagementFixtures|

Usually it is cleaner to hide the imoplementation specifics in configuration files, but it is a good tool to have in the toolbox, for example if there are assemblies that you only want to use on certain test pages of a suite, of which the API conflicts with other assemblies.

Note that if you use this mechanism and you refer to an assembly that doesn't exist, you will not see error messages (like when you use the configuration file) but you will see that tests do not get run. Here is an example of the FitNesseDemo showing that: Test Not Run