How to Unit Test Methods Using Static Methods

static methodsunit testing

Let's assume I wrote an extension method in C# for byte arrays which encodes them into hex strings, as follows:

public static class Extensions
{
    public static string ToHex(this byte[] binary)
    {
        const string chars = "0123456789abcdef";
        var resultBuilder = new StringBuilder();
        foreach(var b in binary)
        {
            resultBuilder.Append(chars[(b >> 4) & 0xf]).Append(chars[b & 0xf]);
        }
        return resultBuilder.ToString();
    }
}

I could test the method above using NUnit as follows:

[Test]
public void TestToHex_Works()
{
    var bytes = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
    Assert.AreEqual("0123456789abcdef", bytes.ToHex());
}

If I use the Extensions.ToHex inside my project, let's assume in Foo.Do method as follows:

public class Foo
{
    public bool Do(byte[] payload)
    {
        var data = "ES=" + payload.ToHex() + "ff";
        // ...
        return data.Length > 5;
    }
    // ...
}

Then all tests of Foo.Do will depend on the success of TestToHex_Works.

Using free functions in C++ the outcome will be the same: tests that test methods that use free functions will depend on the success of free function tests.

How can I handle such situations? Can I somehow resolve these test dependencies? Is there a better way to test the code snippets above?

Best Answer

Then all tests of Foo.Do will depend on the success of TestToHex_Works.

Yes. That's why you have tests for TextToHex. If those tests pass, the function meets the spec defined in those tests. So Foo.Do can safely call it and not worry about it. It's covered already.

You could add an interface, make the method an instance method and inject it into Foo. Then you could mock TextToHex. But now you have to write a mock, which may function differently. So you'll need an "integration" test to bring the two together to ensure the parts really work together. What has that achieved other than making things more complex?

The idea that unit tests should test parts of your code in isolation from other parts is a fallacy. The "unit" in a unit test is an isolated unit of execution. If two tests can be run simultaneously without affecting each other, then they run in isolation and so are unit tests. Static functions that are fast, do not have a complex set up and have no side effects such as your example are therefore fine to use directly in unit tests. If you have code that is slow, complex to set up or has side effects, then mocks are useful. They should be avoided elsewhere though.

Related Topic