About Me

Tuesday, February 22, 2011

How to make Moq object to return different values on each invocation

Today I stacked with the issue how to make Moq function to return different values when its calling by testing unit.

Let's see on example:
[Test]
public void Value_should_be_assigned_on_property_value()
{
///Arrange
...
DrugAgreement agreement = new DrugAgreement();

agreementsManager.Setup(f => f.Create()).Returns(agreement);

///Action
testingUnit.AssignPropertyOnNewlyCreatedObject("propertyValue");

///Assert
Assert.AreEqual("propertyValue", agreement.TestingProperty);
}

The code above expecting that the testing unit will create new instance of the object by calling Create, and change its TestingProperty value to propertyValue

Now, let's implement the code for it:
public DrugAgreement AssignPropertyOnNewlyCreatedObject(string newValue) {
    var obj = manager.Create();
    obj.TestingProperty = newValue;
    return obj;
}

The code above will work as expected.
Now imagine that we mistakenly called Create for the second time after the property was set:
public DrugAgreement AssignPropertyOnNewlyCreatedObject(string newValue) {
    var obj = manager.Create();
    obj.TestingProperty = newValue;
    obj = manager.Create();
    return obj;
}

For the first look, the test above should fail, but it is not!
The test says that TestingProperty is equal to propertyValue, but the object is different. We called Create for the second time and expecting that manager is stateless and don't remember previously returned instance.
The answer is simple - our mock manager returns the same instance of object every time when Create is calling.

So, how to test this ?
How to make sure that Create method is stateless and always returns different objects?

Here is the corrected test:

[Test]
public void Value_should_be_assigned_on_property_value()
{
    ///Arrange
    ...
    DrugAgreement agreement = new DrugAgreement();

    agreementsManager.Setup(f => f.Create()).Returns(agreement).Callback(()=> agreement = new DrugAgreement());

    ///Action
    testingUnit.AssignPropertyOnNewlyCreatedObject("propertyValue");

    ///Assert
    Assert.AreEqual("propertyValue", agreement.TestingProperty);
}

If we test our code now it will fail as it should.
As you can see, the difference in the test is in calling Callback function by moq manager . That function instantiates new instance of DrugAgreement class after each call.

In this case our manager is really stateless and always return different instances

Wednesday, February 16, 2011

Dynamic windows service name

Today i had to install few instances of the same windows service.
Of course they should be named differently.

I found that the name should be set to the ServiceName property of service installer.
This means, that i need to pass a name of the service when I installing it.

I found few solutions, but the most usefull for me, is when the installing is asking me for exact name before it installs the service.
Here is the code that should be placed into the service installer codebehind file (in my case it is ProjectInstaller.cs):
[RunInstaller(true)]
    public partial class ProjectInstaller : Installer
    {
        public ProjectInstaller()
        {
            InitializeComponent();
        }

  private void BeforeInstallEventHandler(object sender, InstallEventArgs e)
  {

   // Add steps to perform any actions before the install process.

   Console.WriteLine("BeforeInstallEventHandler Called");

   Console.WriteLine("Enter the name you would like this service installed as:");

   serviceInstaller.ServiceName = Console.ReadLine();

   PersistServiceName(serviceInstaller.ServiceName);

   Console.WriteLine("Attempting to install service as: " + serviceInstaller.ServiceName);

  }

  private void BeforeUninstallEventHandler(object sender, InstallEventArgs e)
        {

            Console.WriteLine("BeforeUninstallEventHandler Called");

            serviceInstaller.ServiceName = RetrieveServiceName();

            // Add steps to perform any actions before the Uninstall process.

            Console.WriteLine("Code for BeforeUninstallEventHandler");

        }

  /// 
  /// Storing name of the service to the 
  /// config file, for using duing uninstall
  /// process
  /// 
        private void PersistServiceName(string serviceName)
        {

            TextWriter tw = new StreamWriter("Service.config", false);      

            tw.WriteLine(serviceName);

            tw.Close();

        }

  /// 
  /// Getting stored service name from
  /// the file during uninstall process
  /// 
  /// 
        private string RetrieveServiceName()
        {

            string serviceName;


            TextReader tr = new StreamReader("Service.config");

            serviceName = tr.ReadLine();

            tr.Close();

            Console.WriteLine("ServiceName" + serviceName);

            return serviceName;      
        }
    }

Project installer has few events. The code above is using two of them - BeforeInstallEventHandler and BeforeUninstallEventHandler. First one is using to ask the user the service name and store it to the config file.
The second one is using during uninstallation process to retrieve service name from the file and pass it to uninstall process.
Thus, don't forget to open ProjectInstaller.cs designer and assign its BeforeInstall and BeforeUninstall events with appropriate handlers (BeforeInstallEventHandler and BeforeUninstallEventHandler)