Musings<Biefeld>
- curiosities of development, life, the universe and everything -
Posts Tagged ‘Unit Test’
Thursday, August 27th, 2009


Whilst researching using MSpec with ReSharper I found it difficult to find all the resources I needed in one place. This is an attempt to condense everything into that one place and facilitate those seeking to accomplish the same task.

Step 1 – Git It:

First thing’s first, grab the latest Machine Spec source from github.

$ git clone git://github.com/machine.machine.specifications.git mspec

Step 2 – Build It:

Next, open it up in Visual Studio, set it to build in release mode and build it. Now the binaries will be ready for you.

Step 3 – Setup ReSharper:

Now we need to setup ReSharper to be able to utilize the MSpec framework and run the tests in ReSharper’s test runner. To do this we need to add a plugins directory to the “JetBrains\ReSharper\v4.5\Bin” directory or the where ever the bin directory for your ReSharper is located. In the Plugins create a Machine.Specifications directory, so you should now have a path similar to; “JetBrains\ReSharper\v4.5\Bin\Plugins\Machine.Specifications”. Place the following dlls in the newly created folder: Machine.Specifications.ReSharperRunner.4.5.dll and Machine.Specifications.dll.

Step 4 – Write some Specifications:

Coolio, now to test some behaviors, the dlls needed in our test project; Machine.Specifications.dll, Machine.Specifications.NUnit.dll or Machine.Specifications.XUnit.dll, and the appropriate test framework dll.


Let’s take a look at a couple of examples to get used to the syntax. The most common keywords you want to pay attention to are Subject, Establish, Because and It. Declare the Subject of your Spec, Establish a context of the spec, Because x occurs, It should do something. For more complex scenarios you can use the keyword, Behaves_like and the Behaviors attribute which allows you to define complex behaviors. If you need to perform some cleanup use the Cleanup keyword.

Now for a couple of simple contrived examples…

This first specification looks at adding two numbers:

[Subject("adding two operands")]
public class when_adding_two_operands
{
	static decimal value;

	Establish context = () =>
		value = 0m;

	Because of = () =>
		value = new Operator().Add(42.0m, 42.0m);

	It should_add_both_operands = () =>
		value.ShouldEqual(84.0m);
}

The second specification looks at adding multiple numbers:

[Subject("adding multiple operands")]
public class when_adding_multiple_operands
{
	static decimal value;

	Establish context = () =>
		value = 0m;

	Because of = () =>
		value = new Operator().Add(42m, 42m, 42m);

	It should_add_all_operands = () =>
		value.ShouldEqual(126m);
}

The code being tested:

public class Operator
{
	public decimal Add(decimal firstOperand, decimal secondOperand)
	{
		return firstOperand + secondOperand;
	}

	public decimal Add(params decimal[] operands)
	{
		decimal value = 0m;

		foreach (var operand in operands)
		{
			value += operand;
		}

		return value;
	}
}

Step 5 – Create Templates to Improve Your Efficiency:

Using ReSharper templates is a good way to improve your spec writing efficiency, the following are templates I have been using.

This first one is for your normal behaviors:

[Subject("$subject$")]
public class when_$when$
{
	Establish context =()=>	{};

	Because of =()=> {};		

	It should_$should$ =()=> $END$;
}

This one’s for assertions by themselves:

It should_$should$ =()=> $END$;

Step 6 – Run the Report

The report generated is pretty much the exact same as the SpecUnit report. The easiest thing to do is place the following MSpec binaries and file in the directory where your test binaries are placed; CommandLine.dll, Machine.Specifications.ConsoleRunner.exe, Machine.Specifications.dll and CommandLine.xml. The command to run the report goes a little something like:

machine.specifications.consolerunner --html <the location you want the html report stored> <your test dll name>

This is the report generated from the example specs:

MSpecReportExample


Well, that’s about all for now, let me know if you have any questions.


Tuesday, May 12th, 2009


*UPDATE: Per sean chambers, this is an example of the adapter pattern


I recently ran into an issue where I needed to implement a simple email service to send users a randomly generated PIN when they are first entered into the system. To accomplish this I decided to just use the System.Net.Mail implementation.  To create and send an email you have to use the SmtpClient class which does not implement an interface. All I really wanted to test was that the Send() method was called, I did not want to write an integration test that actually sends an email.


One way to work around this problem is to create an interface containing the elements you need to mock from the compiled class.  After this, create your own class that inherits the compiled class and implements your interface. Now when testing, you can seemingly mock up the non-interfaced compiled class, which is exactly what I wanted to achieve. I am not sure whether this is the appropriate way to handle the issue, if anyone has any thoughts on a better way to do this, I would be grateful for the advice.

My specification ended up looking like this:


public class EmailServiceSpecs : ContextSpecification
{
	protected IEmailService _emailService;
	protected ISmtpClient _smtpClient;
	protected string _emailTo = "phillip.fry@planetexpress.com";
	protected string _emailFrom = "hermes.conrad@planetexpress.com";
	protected string _emailSubject = "New Process to Improve Morale";
	protected string _emailBody = "From now on all employees will be required to have Brain slugs, remember, a mindless worker is a happy worker.";

	protected override void SharedContext()
	{
		DependencyInjection.RegisterType<IEmailService, EmailService>();

		_emailService = DependencyInjection
			.GetDependency<IEmailService>(_emailTo, _emailFrom, _emailSubject, _emailBody);

		_smtpClient = MockRepository.GenerateMock<ISmtpClient>();

		DependencyInjection.RegisterInstance(_smtpClient);
	}
}

[TestFixture]
[Concern("Email Service")]
public class when_sending_an_email : EmailServiceSpecs
{
	protected override void Context()
	{
		_smtpClient.Stub(smptClient => smptClient.Send(new MailMessage()))
			.IgnoreArguments()
			.Repeat.Any();

		_emailService.Send();
	}

	[Test]
	[Observation]
	public void should_send_email()
	{
		_smtpClient.AssertWasCalled<
			(smtpClient => smtpClient.Send(new MailMessage()),
			assertionOptions => assertionOptions.IgnoreArguments());
	}
}

Below are my email classes:

public interface ISmtpClient
{
	void Send(MailMessage message);
}

[MapDependency(typeof(ISmtpClient))]
public class SubsideSmtpClient : SmtpClient, ISmtpClient { }

public interface IEmailService
{
	void Send();
}

[MapDependency(typeof(IEmailService))]
public class EmailService : IEmailService
{
	public EmailService(string to, string from, string subject, string body)
	{
		Email = new MailMessage(from, to, subject, body);
	}

	protected MailMessage Email
	{
		get; set;
	}

	private ISmtpClient _smptClient;

	protected ISmtpClient Smtp
	{
		get
		{
			_smptClient = DependencyUtilities
				.RetrieveDependency(_smptClient);
			return _smptClient;
		}
	}

	public void Send()
	{
		Smtp.Send(Email);
	}
}

Musings<Biefeld> is proudly powered by WordPress
Entries (RSS) and Comments (RSS).