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|
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 |
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 |
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 |
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: