I think it's natural to encounter a divide within unit testing. There are many different opinions on how to do it properly and naturally all other opinions are inherently wrong. There are quite a few articles on DrDobbs recently that explore this very issue to which I link at the end of my answer.
The first problem I see with tests is that it's easy to get them wrong. In my college C++ class we were exposed to unit tests in both the first and second semester. We knew nothing about programming in general in either of the semesters- we were trying to learn the fundamentals of programming via C++. Now imagine telling the students, "Oh hey, you wrote a little yearly tax calculator! Now write some unit tests to ensure that it works correctly." The results should be obvious- they were all horrible, including my attempts.
Once you admit that you suck at writing unit tests and wish to get better, you will soon be faced with either trendy styles of testing or different methodologies. By testing methodologies I refer to practices such as test-first or what Andrew Binstock of DrDobbs does, which is write the tests alongside the code. Both have their pros and cons and I refuse to go into any subjective detail because that will incite a flame war. If you're not confused about which programming methodology is better, then maybe the style of testing will do the trick. Should you use TDD, BDD, Property-based testing? JUnit has advanced concepts called Theories that blurs the line between TDD and Property-based testing. Which to use when?
tl;dr It's easy to get testing wrong, it's incredibly opinionated and I don't believe that any one testing methodology is inherently better as long as they are used diligently and professionally within the context that they're appropriate in. Furthermore, testing is in my mind an extension to assertions or sanity-tests that used to ensure a fail-fast ad-hoc approach to development which is now much, much easier.
For a subjective opinion, I prefer to write "phases" of tests, for lack of a better phrase. I write unit tests which test classes in isolation, using mocks where necessary. These will probably be executed with JUnit or something similar. Then I write integration or acceptance tests, these are run separately and usually only a few times a day. These are your non-trivial use case. I usually use BDD as it is nice to express features in natural language, something that JUnit cannot easily provide.
Lastly, resources. These will present conflicting opinions mostly centered around unit testing in different languages and with different frameworks. They should present the divide in ideology and methodology while allowing you to make up your own opinion as long as I haven't manipulated yours too much already :)
[1] The Corruption of Agile by Andrew Binstock
[2] Response to the Responses of the previous article
[3] Response to Corruption of Agile by Uncle Bob
[4]Response to Corruption of Agile by Rob Myers
[5]Why Bother With Cucumber Testing?
[6] You're Cuking it Wrong
[7]Step Away From the Tools
[8]Commentary on 'Roman Numerals Kata with Commentary'
[9]Roman Numerals Kata With Commentary
One quite intuitive way to handle this is to code a truth table into your test so you have something like:
//last in tuple is expected result, rest are inputs
test date = new List<Tuple<bool,bool,bool,bool,string>>()
{
{true,true,true,true,"foo"}
{true,true,true,false,"bar"}
etc...
}
i.e. a data driven test.
For big table you can move this to a data file which you slurp up.
The test itself then simply needs to iterate over the table and plug the inputs in and check the expected output.
This also hints at a possible refactoring of the code. An input of Tuple<bool,bool>
is essentially the same as an enum with 4 possible values.
Best Answer
Unit testing is about behaviour of the code under test from the point of view of its clients. Therefore, as your test class is one of its clients, you should define what are your expectations.
There's a few expectations I see from your implementation :
Therefore, I would expect 6 tests, as there are 6 distinct behaviours I care about as a client.
Quite funny, because I actually believe the reverse is true: you are making too many assumptions about your implementation when you test every combination. Remember that you always test from the point of view of your clients. If you test every single combination, then you're saying that your clients care about all those combinations. My understanding of your code is that it doesn't matter which combination of systems are offline or non functional. As long as one subsystem is offline, then the ship is unavailable, period. Therefore, I would test it as such.
1. Phew, that might require quite of a setup to test this assertion. If that's your feeling as well, then maybe your tests are speaking to you: your code under test is doing quite a lot.