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
Yes. That's why you have tests for
TextToHex
. If those tests pass, the function meets the spec defined in those tests. SoFoo.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 mockTextToHex
. 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.