So, in part 1, we had an overview of what unit tests are and why they matter. Abstraction is a wonderful thing, but meaningless without something concrete to give it context. Without further ado, here’s what a unit test looks like (using C# and .NET Core):
using Xunit;
namespace UnitTestSamples.Tests
{
public class MultiMapTests
{
[Fact]
public void Add_KeyDoesNotExist_AddsValueToNewListForKey()
{
// Arrange
var multiMap = new MultiMap<string, string>();
// Act
var key = "yellow";
var value = "Sun";
multiMap.Add(key, value);
// Assert
Assert.True(multiMap.ContainsKey(key) && multiMap[key].Contains(value));
}
}
}
The method Add_KeyDoesNotExist_AddsValueToNewListForKey
on class MultiMapTests
here is the unit test. We’re using an (excellent) unit test library called xUnit to run the test. The Fact
attribute on the method indicates a test for invariant conditions.
We use a standard pattern here to structure the unit test called Arrange-Act-Assert. Arrange is where we do any setup of initial conditions required for the test. Act is where we exercise the SUT (System Under Test), which in this case is the Add
method on the MultiMap
class. Assert is where we examine the aftermath to determine whether the test succeeded or failed.
There is also another pattern used here to name the test. It is called Action-Scenario-Result. The Add
in the test name is the action under test. KeyDoesNotExist
describes the scenario being tested and AddsValueToNewListForKey
is the expected result. In short, we’re testing whether calling the Add
method with a non-existent key creates a new list with the value and adds it to the multimap.
Another type of test called a Theory is a parameterized test that can be used for varying conditions. The same test can be used for multiple input conditions (the InlineData
attribute on the test method whose values correspond to the parameters of the method).
Since we add only the "yellow"
key to the map, that condition returns true while the non-existent "red"
key returns false.
[Theory]
[InlineData("yellow", true)]
[InlineData("red", false)]
public void ContainsKey_VariousKeys_ReturnsStatus(string key, bool expectedStatus)
{
// Arrange
var multiMap = new MultiMap<string, string>();
// Act
multiMap.Add("yellow", "Sun");
// Assert
Assert.True(multiMap.ContainsKey(key) == expectedStatus);
}
As you can see, there is nothing terribly complex about writing unit tests. We’ll get into more involved tests that use mock objects in a future post, but even there, the idea is to keep the test as simple as possible. If our tests turn out to be overly complicated to setup, that’s a sign that the System Under Test (SUT) could use some refactoring.
https://github.com/cs31415/unit-test-samples
Continue to part 3.