0

If I create a function to calculate the square root of a number, I suppose i should write a single unit test (maybe two, to test how it handles negative numbers).

But what if I have a function which has a lot more possible outcomes. E.g. let's say I have a (simplified) function to calculate your tax rate. It would depend on your income group, but also the year you want to calculate, as tax rates may change over time. Lets say there are 3 income groups and I want to test 10 years back. That's thirty unit tests(!).

How do you test functions with that many outcomes? I could obviously make a loop inside the unit test, but doesn't that kinda violate the concept of a unit test?

  • Not true. That’s X year back and Y income groups, so it’s more like 4 unit tests for this. Even then, thirty unit tests is nothing and should take a very small amount of time to write and pass. That’s the point of unit testing. Fast and easy to understand. – Steve Chamaillard Sep 03 '18 at 13:51
  • @SteveChamaillard I agree that it makes sense in the way that it is easy to understand. However, my example above was quite simplified. In my actual application, having a unit test for each scenario would mean hundreds of unit tests. Is this really the recommended way? – Jakob Busk Sørensen Sep 03 '18 at 13:54
  • @gnat it appears so. I guess the correct way to do it, would be to use NUnit to write a single test and then setup the values it should test. Using the MSTest (Visual Studio default) does not seem to provide any really good options... – Jakob Busk Sørensen Sep 03 '18 at 14:09
  • per my recollection of working with NUnit this sounds like a good plan – gnat Sep 03 '18 at 14:12
  • 1
    If you're using NUnit and are able to parameterise your test, just write a small number of tests with a large number of `[TestCase(...)]` attributes – GoatInTheMachine Sep 03 '18 at 14:48
  • Unit tests aren't really meant to prove without doubt that your code is correct; they represent more of an experimentalist's approach - they (1) help you build some confidence (but not certainty) that the code is correct, and (2) they are a safety net for the purposes of refactoring. So focus on a couple of typical cases, and try to nail down the most important edge cases (or all of them, if possible), because it's the edge cases that often trip you up. That said, you should still check this kind of code for correctness manually (refactor and simplify to facilitate that where necessary). – Filip Milovanović Sep 03 '18 at 15:52
  • 1
    P.S. "but doesn't [... a loop ...] kinda violate the concept of a unit test?" Not really. Yes, there are ways to avoid loops, but conceptually, unit tests are meant to be readable (so that the intent of the test is clear), and execute fast to provide next-to-instant feedback, with a good failure message. If you can make these happen, a loop is not really a problem in any significant way (and you can hide it in a helper method). – Filip Milovanović Sep 03 '18 at 15:55

0 Answers0