Use data-transfer objects directly

Mapping columns to properties becomes quite cumbersome with more complex objects. In real-life projects, domain packages probably already have a good data-transfer object (DTO), so this direct mapping just complicates test classes unnecessarily. FitNesse allows us to use a data-transfer object directly without declaring all its properties in a fixture class. In order to do that, we override the GetTargetObject method of the Fixture class to specify our DTO. In this case, we use the PlayerRegistrationInfo class,[15] which implements the IPlayerRegistration data-transfer interface.

When GetTargetObject is overriden, the fixture class tells FitNesse how to execute tests, but does not directly provide the test implementation. For example, our fixture can just tell FitNesse to execute a ColumnFixture test, but the target object has to implement properties and methods for table columns. When a target object is provided, all table columns must be bound to this object. You cannot mix and match — the whole table is mapped either to the fixture or to the target object. This includes test methods and additional setup columns, which do not exist in the DTO object. I typically solve this by creating an inner class in the fixture that extends the DTO class with test methods.

Tristan/test/PlayerRegistration.cs


68    public class PlayerRegisters : ColumnFixture
69    {
70      public class ExtendedPlayerRegistrationInfo: PlayerRegistrationInfo 
71      {
72        public int PlayerId() 
73        {
74          return SetUpTestEnvironment.playerManager.RegisterPlayer(this);
75        }  
76      }
77      private ExtendedPlayerRegistrationInfo to = 
78        new ExtendedPlayerRegistrationInfo();
79      public override object  GetTargetObject() 
80      {
81          return to;
82      }
83    }

We can use this technique to fill in all the PlayerRegistrationInfo properties without redeclaring them in fixture code, and then use a ready-made DTO as an input for test methods. We can use a similar approach for binding DTO properties to columns that contain expected test results. Theoretically, we could use the same table row to store the player ID and read other properties into the DTO, but this would require copying values from one DTO object to another. The target object can be switched at run time, which is a good way to solve this problem in Java, but because C# inner classes do not have access to outer class instances, this would not be a clean solution. It is much better to use a fixture argument (see Replace repetitive values with arguments) to load the DTO. Sometimes it is quite convenient to use a FitNesse symbol value as the argument, as in this case, because the new player ID is already in a symbol. However, symbols cannot be directly used as arguments.[16] We can pass the symbol name as an argument and read it in the test class, using Fixture.Recall(symbolName). Note that you should not use >> or << in this case, just the plain symbol name.

Tristan/test/PlayerRegistration.cs


84    public class CheckStoredDetailsFor : ColumnFixture
85    {
86      public override object GetTargetObject() 
87      {
88        int newid=(int)Fixture.Recall(Args[0]);
89        return SetUpTestEnvironment.playerManager.GetPlayer(newid);    
90      }      
91    }



[16] There is a patch that provides this functionality, see http://gojko.net/fitnesse.