Freigeben über


Introducing EMTF

A while ago a needed to do what I like to call quick and dirty testing, i.e. getting as much test coverage as possible in a given period of time. To make things worse, I was working on a client-server feature requiring a bit of setup in order to work in the first place and wanted to cover both sides with my tests and be able to easily run all tests. So I thought, what if instead of trying to get this done with one of the existing test frameworks that typically host the test target as well as its tests, I just created a new solution which already had all the pieces in place to use the feature and put a tiny test runtime in there. I did exactly that and got my testing done the way I wanted to. Again, there is a reason why I call this kind of approach quick and dirty testing and I definitely wouldn't pitch it as a best practice but it has its place.

Because of my objective this "embedded" test runtime I created was extremely small but also highly specific to the test scenarios for which it was written and thus virtually impossible to reuse. That wasn't a surprise but rather one of the tradeoffs I had opted in for. Still, I was wondering what a generalized version would look like that, next time I wanted to do something like this, I could simply drop into my application and get going. The answer to that question is EMTF.

Yet another test framework called EMTF

The Embeddable Micro Test Framework is similar to its big brothers MSTest or NUnit though obviously smaller and simpler and with the twist of it being supposed to be hosted by the application under test rather than coming with its own test host. It is available in source and binary form on CodePlex and by now I'd say that its greatest value is actually in using it for educational purposes since the reduced complexity makes it easy to understand for people without prior API testing experience (that goes for both how to use it and - at the core - how it works). That said the rest of this post is an EMTF quickstart (though I do consider a small series on how to implement an API test framework using EMTF as an example).

The easiest way to add EMTF to your project (especially if you're not using C#) is to add references to the two assemblies Emtf.dll and Emtf.Logging.dll. The first assembly contains the actual test framework that doesn't even include any logging capabilities. The second one contains a logging base class, a logger writing to the debug output and a logger writing to the console (the latter one only for the .NET Framework). There are separate versions of the two assemblies for Silverlight and the .NET Framework with the Silverlight version being a subset.

Writing tests

Let's say your project is a console application, you added EMTF to it and now want to test the following class which is part of your project (once again, please ignore the fact that the class is completely useless):

public class LameExample

{

    private String _string;

    public String String

    {

        get

        {

            return _string;

        }

        set

        {

            if (value == String.Empty)

                throw new ArgumentException(

                    "New value must not be an empty string.",

                    "value");

            _string = value;

        }

    }

}

We need to verify that:

  1. The default value of the String property is null
  2. The setter of the String property throws an ArgumentException if we pass in String.Empty
  3. We can set the property to arbitrary values (except for String.Empty)

Ideally we want the test framework to automatically find all the tests and execute them. So in order to tell EMTF which classes contain tests, they need to be marked with the TestClassAttribute. Furthermore, test classes must be public, non-abstract and non-generic since the runtime wouldn't know which type parameters to use. Similarly, test methods are marked with the TestAttribute and must be public, non-abstract and non-generic. In addition, their return type must be void and they must not take any parameters. Tests for state and behavior of an object are performed using assertions.

[TestClass]

public class LameExampleTests

{

    [Test]

    public void StringProperty()

    {

        LameExample le = new LameExample();

        // Verifies the default value of LameExample.String

        Assert.IsNull(le.String);

        // Verifies that the setter throws

    Assert.Throws(

            // Action that is expected to cause the exception

            () => le.String = String.Empty,

            // Action(T) verifying the exception object where

            // T is the type of the expected exception.

            (ArgumentException e) =>

            {

                Assert.IsTrue(e.Message.StartsWith("New value must not be an empty string."));

                Assert.AreEqual("value", e.ParamName);

            });

        // Verifies setting the property to a non-null,

        // non-empty string.

        le.String = "fhqwhgads";

        Assert.AreEqual("fhqwhgads", le.String);

        // Verifies resetting the property to null.

        le.String = null;

        Assert.IsNull(le.String);

    }

}

Running the tests

Since EMTF does not include any sort of test host we need to instantiate the engine, the TestExecutor, ourselves. In addition, we need to hookup the engine's events so we actually get to know the outcome of the test run. The loggers in Emtf.Logging.dll do this out of the box. Finally, calling TestExecutor.Execute() will execute all the tests we have defined that conform to the rules explained above.

private static void RunTests()

{

    TestExecutor executor = new TestExecutor();

    ConsoleLogger logger = new ConsoleLogger(executor);

    executor.Execute();

}

EMTF ConsoleLogger


This posting is provided "AS IS" with no warranties, and confers no rights.

EMTF Console Sample Screenshot.png