Hi Sean,
Makes sense. Looks like a new ScalaTest feature may be justified. Just
in time too, because it would require an additional event added to the
event model, and that's a 2.0 "event."
The event would need to be a different from TestCanceled, TestIgnored,
or TestPending, because those have specific meanings that are
different from this. I've tried to avoid "skipped" because in English
a test is indeed skipped if it is canceled, ignored, or pending, and
that's what Maven and sbt, etc., print out for any of those. The best
I have come up with so far is TestOmitted. This would mean the test
either wasn't run at all, or if it was run, the result was dropped and
TestOmitted fired instead.
We have done the RunArgs refactor already in the trunk, which
simplifies the four run lifecycle method signatures. So I could add an
omitTests: Boolean flag to RunArgs. If you want tests to be omitted,
you'd set that flag. We'd provide a way to do so via runner, the build
tools, and the ScalaTest shell. I think we'd also need a
runOmittedTests: Boolean flag, initalized to false. More on that
later.
I'd want the output to look different. It certainly shouldn't look
like everything passed. So for the standard out or file reporter,
perhaps I'd turn color off and have a (tests omitted) next to the
Suite name.
StackSpec: (tests omitted)
A Stack
when empty
- should be empty
- should complain on pop
Similar visual differences in other reporters.
If a test is not executed, then I wouldn't know if it succeeded,
failed, was pending, or canceled. But I would know if it was ignored,
because that's known in advance of executing a test. So one question I
have for you is, would you want to see ignored notifications in the
output, or would you want TestIgnored events replaced by TestOmitted
events as well?
Then for cases like yours where you want the given/when/thens inside
the tests to show up in the structure output, perhaps we could offer a
OmittedTestCode trait. It would override run, and if omitTests is
true, set a volatile Boolean omit flag declared in the trait, then
call super.run with runOmittedTests in the RunArgs set to true. That
will cause the suite to actually run the tests, but fire a TestOmitted
event regardless of the result.
Now on to omitting slow test code. I'm confident there's a satisfying
way to avoid using a non-obvious operator if we look hard enough.
Would this be too wordy? For slow side effecting things, could you
write:
if (!omit) doTheSlowSideEffectingThing()
The volatile omit flag would be set by the run method and therefore
available to the tests. For things that require a T, could you do
something like:
val user = if (!omit) createUser("Bob") else null
The ugly null is in there, but the code is obvious. Could possibly
provide a default method that takes a T:
val user = if (!omit) createUser("Bob") else default[User]
An implicit could get you something like:
val user = createUser("Bob") orOmitAs null
or:
val user = createUser("Bob") orOmitAs default
Something along those lines? We could consider something like you %>
but the obvious text is a bit verbose I think:
unlessOmitted {
doTheSlowSideEffectingThing()
}
or:
val user = unlessOmitted {
createUser("Bob")
}
Maybe not so bad, though for the latter it is not obvious what user is
getting assigned if omit is set.
Bill