NAnt + NUnit: Using a Build Script to Run All Test Projects Within a Solution

Filed Under (.Net) by John Miller on 17-02-2009

Tagged Under : , ,

Occasionally my solutions include multiple test projects. And I’d like NAnt to automatically save pick up the new test projects as their added without having to modify the build script. Turns out that there are a couple of ways to do this.

Method 1

<target name="run.tests" description="Runs tests for all test projects in solution."
  depends="compile">
  <nunit2 verbose="true" haltonfailure="false" failonerror="true">
    <formatter type="Plain" extension=".txt" usefile="true" outputdir="${out.dir}"/>
    <test haltonfailure="false">
      <assemblies>
        <include name="${solution.dir}\**\bin\${build.configuration}\*Tests.dll" />
      </assemblies>
    </test>
  </nunit2>
</target>

This one will pick up all dlls for projects ending with the word Tests (the naming convention that all of my test projects currently follow). The down side here is that if I want to run all tests regardless of any failures, I have to set haltonfailure="true". But I have another target that depends on this one that creates test documentation based the results, and I only want that target to run if all the tests pass. So I’d have to fail the build on the first failed test, which I don’t want to do.

Method 2

My solution was iterate through the test project dlls and use an exec task to run the the nunit-console. By doing this, we can look at the result property that is returned to determine if any tests failed. If any fail, we set the "all.tests.passed" variable to false, which is used at the end of the task to determine if the build should fail or if it can safely move on to the next task.

<target name="run.tests" description="Runs tests for all test projects in solution."
  depends="compile">
  <property name="all.tests.passed" value='true' />

  <foreach item="File" property="test.project">
    <in>
      <items basedir="${solution.dir}">
        <include name="**bin\${build.configuration}\*Tests.dll"/>
      </items>
    </in>
    <do>
      <exec program="${nunit.exe.dir}\nunit-console.exe"
        commandline="${doublequotes}${test.project}${doublequotes}
        /xml=${doublequotes}${out.dir}/${path::get-file-name(test.project)}-Results.xml${doublequotes}"
        workingdir="." failonerror="false" resultproperty="test.result" />

      <if test="${int::parse(test.result) != 0}">
        <property name="all.tests.passed" value='false' />
      </if>
    </do>
  </foreach>

  <fail message="Failure reported in one or more unit tests."
    unless="${all.tests.passed == 'true'}" />
</target>
DotNetKicks Image

Share/Save/Bookmark

Testing for Expected Exceptions Without Compromising BDD Conventions

Filed Under (.Net, Unit Testing) by John Miller on 10-02-2009

Tagged Under : , , ,

Today I decided to relearn some of the BDD concepts I picked up at the end of last year and ran into a scenario where I needed to test that a specific type of exception was being thrown by a method. The simple way to do this is to decorate your test method with an ExpectedException attribute, but that forces you to combine the Act/Assert parts of your test.

Not happy with that solution I decided that I would rather catch the exception in one part of my test and validate it’s type later. In the end, I created a helper class to do some of the work:

public class ExceptionTestHelper
{
    public static Exception CatchException(Action action)
    {
        try
        {
            action.Invoke();
        }
        catch (Exception ex)
        {
            return ex;
        }

        return null;
    }
}

Pretty simple. And now our tests seem a little more natural.

[TestFixture]
public class When_asked_to_get_a_users_goals_using_an_invalid_user_id
    : GoalsServiceTestBase
{
    private Exception caughtException;

    protected override void because()
    {
        base.because();
        caughtException =
            ExceptionTestHelper.CatchException(
                () => goalsService.GetGoalsForUser(-1));
    }

    [Test]
    public void should_throw_an_argument_exception()
    {
        Assert.That(caughtException,
            Is.InstanceOfType(typeof(ArgumentException)));
    }
 }

 

public abstract class GoalsServiceTestBase : TestBase

{
    protected IGoalsRepository stubGoalsRepository;
    protected IGoalsService goalsService;
    protected Goal stubGoal;

    protected override void  establish_context()
    {
        base.establish_context();
        stubGoalsRepository =
            MockRepository.GenerateStub<IGoalsRepository>();
        goalsService = new GoalsService(stubGoalsRepository);
        stubGoal = new Goal();
    }
}
[TestFixture]
public abstract class TestBase
{
    [SetUp]
    public void setup()
    {
        establish_context();
        because();
    }

    protected virtual void establish_context()
    { }

    protected virtual void because()
    { }
}

At first glance I like it. Although I’m sure that someone out there that may have a better solution that still sticks with our BDD approach.

DotNetKicks Image

Share/Save/Bookmark