Hi Ken,
Thanks for the detailed response. I have been considering adding a
verbose message alternative in TestFailedException, which would give
extra information if it exists. Your response adds momentum to that. I
will also consider allowing triple-equals expressions to be logically
combined, such as with &&, so it could be taken advantage of by
writing assertion as well as matcher expressions. I'd also provide a
way to indicate you want the verbose message copied to the regular
message, so it shows up in the results, as well as see if IDEs can
give you the option to see it either way.
One other place this has shown up is in table-driven property checks.
Users might want to see just the first row that failed, or might want
to see how the entire table did. This could be done via the same
mechanism.
For now, though, I think you're mostly stuck with seeing one failure
at a time, or splitting out your assertions into individual tests. I
think you could minimize the scope of the shared data with a block,
like this:
{ // Just open a block in the FunSuite constructor you're writing
val tree = new Line -> (
new Line -> (
"a",
new Line -> ("b", "c"),
new Line -> ("d"),
"e"
)
)
def leaf(s: String): Leaf = tree.findLeaves(_.text==s)(0)
// And define the tests inside the block
test("nextLeaf finds the next leaf inside a new line") {
assert(leaf("a").nextLeaf(1, Forward).get.text === "b")
}
test("nextLeaf finds the next leaf inside the same line") {
assert(leaf("b").nextLeaf(1, Forward).get.text === "c")
}
test("nextLeaf finds the next leaf inside a parent line") {
assert(leaf("c").nextLeaf(1, Forward).get.text === "d")
}
} // Close the block and continue with more tests below...
By the way I'd say that although doing it this way is a bit more
verbose, I think it does make more clear the three different scenarios
you were writing assertions for.
Bill
Post by Ken McDonaldHi Bill, thanks for getting back to me so quickly.
I've always done things in this manner, and found it useful. I group
1) When they all test slightly different aspects of the "same thing". For
example, in my original post, all of the assertions are testing navigation
in a tree structure, and each assertion exercises (if I've don't my job
right) a different condition in the code that travels the links between tree
nodes.
2) They all test different behavior on the same object; in this case, having
all of the assertions together makes it easy to see that all behaviors on
that object have been tested.
3) I more often than not try to make my tests "functional", in the standard
sense; there is no state change in the objects being tested. This means
multiple assertions can be meaningfully run in the same test, since an error
reported by one isn't caused by something that will cascade to other
assertions.
4) And yes, your point about having multiple assertions in a single test aid
in diagnosis is something I've certainly found to be true. Going back to my
original posting (where there will probably be a total of about eight
assertions), if say two failed and the others succeeded, that often lets me
construct in my head exactly the code path that must have caused the
problem.
I certainly could pull out local objects into fixtures and use only one
assertion per test, but that really expands out the code while (IMHO) making
it less readable because I cannot write closely related assertions adjacent
to one another, nor can see them right next to the data structure they are
testing on. Plus, of course, if it's easier to write more actual test code,
it's likely more of it will be written.
Cheers,
Ken
--
Bill Venners
Artima, Inc.
http://www.artima.com