Here\'s a basic example of what my unit test needs to be, using qunit: <!DOCTYPE
ID: 647178 • Letter: H
Question
Here's a basic example of what my unit test needs to be, using qunit:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<link rel="stylesheet" href="qunit/qunit-1.13.0.css">
<script src="qunit/qunit-1.13.0.js"></script>
<script src="../js/fuzzQuery.js"></script>
<script>
test("Fuzz Query Basics", function()
{
equal(fuzzQuery("name:(John Smith)"), "name:(John~ Smith~)");
equal(fuzzQuery("name:Jon~0.1"), "name:Jon~0.1");
equal(fuzzQuery("Jon"), "Jon~");
//etc
}
);
</script>
</head>
<body>
<div id="qunit"></div>
</body>
</html>
Now I was thinking this is a bit repetitive.
Could put all the inputs/outputs into an array, and loop through it.
test("Fuzz Query Basics", function()
{
var equals = [
["name:(John Smith)", "name:(John~ Smith~)"],
["name:Jon~0.1", "name:Jon~0.1"],
["Jon", "Jon~"]
];
for (var i = 0; i<equals.length; i++)
{
equal(fuzzQuery(equals[i][0]), equals[i][1]);
}
}
);
And this works fine.
The single advantage I can think of for this second method, is that if it turns out that you don't actually want to use equal it's easier to make that change in one spot.
In terms of readability, I don't think it's conclusive either way, though I probably prefer the second.
Abstracting it further, you could put the input/output cases into a separate CSV file, which might make it easier to modify.
Question is - what are the general conventions around writing these kinds of unit tests?
Is there a reason you shouldn't put them into arrays?
Explanation / Answer
Your refactored tests have a smell: Conditional Test Logic.
The reasons you should avoid writing conditional logic in your tests are two-fold. The first is that it undermines your ability to be confident that your test code is correct, as described in the linked xUnit Patterns article.
The second is that it obscures the meaning of the tests. We write Test Methods because they put the logic for testing a given behaviour in one place, and allow us to give it a descriptive name (see Dan North's original BDD article for an exploration of the value of good names for tests). When your tests are hidden inside a single function with a for loop, it obscures the meaning of the code for the reader. Not only does the reader have to comprehend the loop, they also have to mentally unravel all the different behaviours being tested within the loop.
The solution, as always, is to move up a level of abstraction. Use a test framework which gives you parametrised tests, like xUnit.NET or Contexts do (disclaimer: I wrote Contexts). This allows you to group triangulating tests for the same behaviour together in a natural way, while keeping tests for separate behaviours separate.