views:

363

answers:

4

I want to be better at using NUnit for testing the applications I write, but I often find that the unit tests I write have a direct link to the environment or underlying database on the development machine instead.

Let me make an example.

I'm writing a class which has the single responsibility of retriving a string, which has been stored in the registry by another application. The key is stored in HKCU\Software\CustomApplication\IniPath.

The Test I end up writing looks like this;

[Test]
public void GetIniDir()
{
    RegistryReader r = new RegistryReader();
    Assert.AreEqual(@"C:\Programfiles\CustomApplication\SomeDir", r.IniDir);
}

But the problem here is that the string @"C:\Programfiles\CustomApplication\SomeDir" is really just correct right now. Tomorrow it might have changed to @"C:\Anotherdir\SomeDir", and suddenly that breaks my unit tests, even though the code hasn't changed.

This problem is also seen when I create a class which does CRUD operations against a database. The data in the database can change all the time, and this in turn makes the tests fail. So even if my class does what it is intended to do it will fail because the database returns more customers that it had when I originally wrote the test.

[Test]
public void GetAllCustomersCount()
{
    DAL d = new DAL();
    Assert.AreEqual(249, d.GetCustomerCount());
}

Do you guys have any tips on writing Tests which do not rely on the surrounding environment as much?

+6  A: 

The solution to this problem is well-known: mocking. Refactor your code to interfaces, then develop fake classes to implement those interfaces or mock them with a mocking framework, such as RhinoMocks, easyMock, Moq, et. al. Using fake or mock classes allow you to define what the interface returns for your test without having to actually interact with the external entity, such as a database.

For more info on mocking via SO, try this Google search: http://www.google.com/search?q=mock+site:stackoverflow.com. You may also be interesting in the definitions at: http://stackoverflow.com/questions/346372/whats-the-difference-between-faking-mocking-and-stubbing

Additionally, good development practices, such as dependency injection (as @Patrik suggests), which allows the decoupling of your classes from its dependencies, and the avoidance of static objects, which makes unit testing harder, will facilitate your testing. Using TDD practices -- where the tests are developed first -- will help you to naturally develop applications that incorporate these design principles.

tvanfosson
A: 

Other way is to create separate database for tests.

Migol
But then you're not really unit testing, you're integration testing.
Patrik Hägne
+1  A: 

The easiest way is to make the dependencies explicit using dependency injection. For example, your first example has a dependency on the registry, make this dependency explicit by passing an IRegistry (an interface that you'll define) instance and then only use this passed in dependency to read from the registry. This way you can pass in an IRegistry-stub when testing that always return a known value, in production you instead use an implementation that actually reads from the registry.

public interface IRegistry
{
    string GetCurrentUserValue(string key);
}

public class RegistryReader
{
    public RegistryReader(IRegistry registry)
    { 
        ...
        // make the dependency explicit in the constructor.
    }
}
[TestFixture]
public class RegistryReaderTests
{
    [Test]
    public void Foo_test()
    { 
        var stub = new StubRegistry();
        stub.ReturnValue = "known value";

        RegistryReader testedReader = new RegistryReader(stub);

        // test here...
    }

    public class StubRegistry
        : IRegistry
    {
        public string ReturnValue;

        public string GetCurrentUserValue(string key)
        {
            return ReturnValue;
        }
    }
}

In this quick example i use manual stubbing, of course you could use any mocking framework for this.

Patrik Hägne
A: 

You should read up on the inversion of control principle and how to use the dependency injection technique - that really helps you write testable code.

In your case, you should probably have an interface - e.g. IIniDirProvider - which is implemented by RegistryBasedIniDirProvider, which is resposible for providing the initial directory based off a specific key in the registry.

Then, when some other class needs to look up the initial directory, that other class should have the following ctor:

public SomeOtherClass(IIniDirProvider iniDirProvider)
{
    this.iniDirProvider = iniDirProvider;
}

-allowing you to pass in a mock IIniDirProvider when you need to unit test SomeOtherClass. That way your unit test will not depend on anything being present in the registry.

mookid8000