Unit testing - same method but for different test data
This is pretty basic question around unit testing.
I have a method e.g. GetOrderDetails which calls a Repository to fetch order details. I have a mock repository which can be setup to return stock responses.
For testing GetOrderDetails method, I'll at least use the following cases -
Repository call fails
- with an error code
- with 开发者_开发知识库an Exception
Repository call succeeded
- returned zero result
- returned one result
- returned more than one result
Should I be writing a single Test method to test above scenarios or should it really be a seperate test method for each of the above scenario?
I believe, breaking it down into multiple test methods would at least provide the following benefits 1. higher isolation in case of test failures 2. amount of code within a test method is less 3. each test method will have a single repository setup responsibility e.g. either setup for no result, or setup for multiple results etc
Could you please help with your views around this?
I would write a separate unit test for each case. Basically every time you write an if
or a switch
inside the method you are testing it implies different unit tests to handle each case. The reason for this is that the arrange part of your unit test will be different based on which route you would like your code to take (different mock expectations, property setups, ...). Also I would recommend you to organize your unit test in the following three parts:
// arrange
// -> prepare mock objects, properties, setup expectations
// act
// -> invoke the method your are testing
// assert
// -> assert on the results returned by the method your are testing
I know some people might set up a data-driven test method that executes based on varying criteria in a data source, but I prefer individual methods, particularly since that allows me to give it a meaningful name along the lines of MethodName_StateUnderTest_ExpectedResult (a naming convention championed by agile/unit testing coach and author Roy Osherove, among others). I can look at the name and immediately know what passed or failed, not have to wonder what variation may have passed or failed. It also helps that my unit test isn't dependent upon the file system.
This is really a subjective question and you will get varied answers. A few things to keep in mind.
Keep the test code short and sweet. I try to fit all my unit test functions in one screen. If I can do that, than I put anything in there I want to. I certainly test more than one thing in a particular function as long the overlying method is short.
duplicating code unit tests, with only one variable difference is a maintenance nightmare. Imagine having 5 unit tests, each containing 40 lines of code, and the only difference between them is a silly return value. If you do that, you will be scratching your head in 6 months.
Use a code coverage tool while writing unit tests. I can't over emphasize that. It will help you identify areas that are you not testing. I have found it helps me eliminate dead code as well, since less code is less potential bugs.
The most complicated logic I ever put in a unit test, is a for loop. And that is only to initialize a simple array, if it is needed for something specific to the test. I always steer clear of if statements in unit tests. But if are using data driven tests, a for loop is just fine to feed data into your tests, if you need to do it. But if the for loop is small, feel free to unroll the loop too.
I hope some of that advice helps.
精彩评论