1

I have a functions class that does various functions (shocking, I know). One such function is to return a list of public holidays for the given year(s). Each calculation has it's own private function, so the public function really just compiles the various holidays into a list.

Now I want to run some tests on this, obviously I can't run tests on the private methods, so I pull out the list in the TestInitialize method and then work with that for various tests.

The problem is, say I pull out New Year's Day with something like list.SingleOrDefault(p => p.HolidayName.Equals("New Year's Day")), it's then best to check if it's null or not before running the intended test (it should be on a weekday, which as far as I can tell is two asserts in itself...).

So, two questions I suppose.
1. Is this situation an exception to the rule 1 assert per unit test? Or do I need to separate out the null assertion and the weekend assertion?
2. As far as I can tell, there would be two assertions to make sure it's not on a weekend; one to check if day of week is not equal to saturday and one to check if day of week is not equal to sunday. Or am I wrong here?

Trent
  • 1,595
  • 15
  • 37
  • 1
    Why can't you just test the public methods? If those are working, one can assume the private methods they are calling are working correctly. No? – TyCobb Nov 15 '13 at 05:01
  • Well I could yeah. I still have the issue of pulling out each Public Holiday from the list and checking if it's not null, and correct. – Trent Nov 15 '13 at 05:25
  • Maybe its me. It seems nitpicky to debate whether you should check for null here or there. As long as you verify the data does it really matter? As for question #2 yea sure if you are worried about domain overflow do it. In other words if you are testing an `int` then 1 + 1 = 2 is a sufficient assertion. 2 + 2 = 4 is unecessary because it tests the same domain. Other domains that still need testing are negative #'s and large #'s. – P.Brian.Mackey Nov 15 '13 at 05:30

2 Answers2

4

One such function is to return a list of public holidays for the given year(s).

This is your contract and this is what you should be testing.

Each calculation has it's own private function, so the public function really just compiles the various holidays into a list.

This is irrelevant and you shouldn't be concerned about how stuff looks from inside.

Now, having said that your main method will require 1 unit test per expected holiday in given year. In such test you'll check holiday details: days, dates, names - with multiple asserts. Other than that, your method might need some boundaries check (since it works on years range) and input values verification (like, making sure year actually represents year).

Few advices:

  • when testing, always try to think what would my method caller expect? Then write tests around those assumptions. Your caller expects list of holidays, and that should be your primary focus when testing this method.
  • 1 assert per test is very dangerous misconception. It's not about single Assert.AreEqual ... call - it's about verifying one logical concept (as mentioned here or here). In your case, holiday is such concept. You verify it (assert its correctness) by checking all required properties. Knowing that holiday has correct date is worthless unless you know what holiday it is.
Community
  • 1
  • 1
k.m
  • 30,794
  • 10
  • 62
  • 86
  • OK, great. That's as I thought, thanks for the confirmation. Between yourself and Ondrej I think I've got my answer. – Trent Dec 02 '13 at 00:28
3

You already know that you can't test private methods, but you can test internal methods if it would give sense to make them internal in your case. If it does not give sense, let them be private and test them as you are trying to.

As for the first concern, you don't really have to abide by every rule out there. If you are a single person on the project, follow you feelings. I can't think of any test I have ever written that would have only one assert included. Most test frameworks can point out what exactly went wrong during a test. It gives a perfect sense to first check null and then check an expected value.

As for the second question, you don't really need two asserts at all. It would give sense to have days recognized in your application like enum values.

public enum WeekDays
{
    Monday = 0
    Tuesday = 1
    ...
}

You could then easily assert as follows

Assert.IsTrue(holiday.WeekDay < WeekDays.Saturday);

You don't even have to specify int values for week days in case you are starting there from Monday. If you have Sunday at the top, make sure you give it a value 6 and Monday would be 0. Read more about underlying enum values on MSDN.

If you can't or don't want to have it as enum, you can still make it with one assert, althought it would not be so nifty.

Assert.IsFalse(holiday.WeekDay.StartsWith("S")); // assuming that the WeekDay is a string
Bridge
  • 29,818
  • 9
  • 60
  • 82
Ondrej Janacek
  • 12,486
  • 14
  • 59
  • 93
  • A simple less than check, of course -_- Brain must have been in meltdown when I asked that. – Trent Dec 02 '13 at 00:26
  • And thanks for the clarification of multiple asserts, jimmy_keen has also said the same and yeah, to me even though the "rules" say 1 assert, testing for null first makes a lot of sense. I'm guess the rules were written back when test frameworks were pretty basic. – Trent Dec 02 '13 at 00:27