Monday, 27 May 2013

First Time NSpec with Visual Studio 2012

There are many different tools to do Behaviour Driven Development (BDD) practice. One of them is NSpec. In this post, I described the first step of how to use it with Visual Studio 2012.

Firstly we need to install NSpec and NSpec adapter for xUnit on our test project, we can use Package Manager to install those easily.

Then add a class in the project and put the code below:
using NSpec;
 
class my_first_spec : nspec
{
    void given_the_world_has_not_come_to_an_end()
    {
        it["Hello World should be Hello World"] = () => "Hello World".should_be("Hello World");
    }
}

Build the project then run this command on Package Manager Console:
nspecrunner [your_test_project]\bin\debug\[your_test_project].dll
You should get this result:
my first spec
  given the world has not come to an end
    Hello World should be Hello World

1 Examples, 0 Failed, 0 Pending

If you had this error "The term 'nspecrunner' is not recognized as the name of a cmdlet, function, script file, or operable program" then it seems that the files are not copied properly by PM. You could resolve this issue by manually copying the missing files.
Go to '[your_solution_folder]\packages\nspec.0.9.66\tools' folder then copy these two files; NSpecRunner and NSpecRunner.exe, to '[your_project_folder]\bin\debug' folder.
Restart Visual Studio then run the command again.

Friday, 17 May 2013

Modifying Passed Object to a Mocked Interface's Method

For instance we have a mockable interface with a method accepting an object that modifies its property inside without returning back the new property value. The new value however is required by subsequence codes. For example:
public void InsertOrUpdate(Invoice invoice)
{
   . . .
   context.Add<Invoice>(invoice); // this method will save to database and generate an Id
   
   int generatedId = invoice.InvoiceId; // the Id is required for subsequence codes
   . . .
}
Now how do we do this in our unit test with Moq? We can use Callback feature to modify the object passed then go on with our testing:
// Arrange
Mock<IDomainContext> context = new Mock<IDomainContext>();
InvoiceDS invoiceDS = new InvoiceDS(context.Object);
  //set up so that after context.Add<Invoice>(invoice) is called, InvoiceId is set to 5
context.Setup(c => c.Add<Invoice>(It.IsAny<Invoice>())).Callback<Invoice>(i => i.InvoiceId = 5);
Invoice invoice = new Invoice();

// Act
invoiceDS.InsertOrUpdate(invoice);

// Assert
. . .