HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Unit Tests for getting the first Monday of the month

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thetestsgettingfirstformonthmondayunit

Problem

I have an application that runs hourly, and I want to use it to also send an email at the start of the day of the first Monday of the month. I searched and found information to help me code what I needed, and all my tests pass, but I want to make sure that I am testing for all edge cases and that I am also being a good little programmer and writing good code.

I have the application being called from a task scheduler on the hour, sometimes some of the code doesn't get called right on the hour.

My Code for checking the date:

public bool CheckSendNewEvent()
{
    var now = DateTime.Now;
    const int SendTime = 8;
    var firstMonday = GetFirstMondayofMonth(now);
    var timeToSendOnFirstMonday = new DateTime(firstMonday.Year, firstMonday.Month, firstMonday.Day, SendTime, 0, 0);
    return now > timeToSendOnFirstMonday && now  timeToSendOnFirstMonday && now Gets the first week day following a date.
///The date.
///The day of week to return.
///The first dayOfWeek day following date, or date if it is on dayOfWeek.
public static DateTime Next(DateTime date, DayOfWeek dayOfWeek)
{
    return date.AddDays((dayOfWeek < date.DayOfWeek ? 7 : 0) + dayOfWeek - date.DayOfWeek);
}

public static DateTime GetFirstMondayofMonth(DateTime now)
{
    var monday = new DateTime(now.Year, now.Month, 1);
    monday = Next(monday, DayOfWeek.Monday);
    return monday;
}


I hate to admit this, but I am pretty much a beginner when it comes to Unit Tests, and I think that my life would be much easier with them, so I want to make sure that I am starting out with good habits.

Some of these tests were written before and after reading some articles about naming tests, hence the reason for the bad naming consistency

So here are my tests:

```
[TestMethod]
public void CheckSendNewEvent_Test()
{
var program = new Program();
var checker = program.CheckSendNewEvent();
Assert.AreEqual(false, checker);

}
[TestMethod]
public void CheckSendNewEvent_MinDate()
{
var checker =

Solution

public bool CheckSendNewEvent()
{
    var now = DateTime.Now;
    const int SendTime = 8;
    var firstMonday = GetFirstMondayofMonth(now);
    var timeToSendOnFirstMonday = new DateTime(firstMonday.Year, firstMonday.Month, firstMonday.Day, SendTime, 0, 0);
    return now > timeToSendOnFirstMonday && now  timeToSendOnFirstMonday && now < (timeToSendOnFirstMonday.AddHours(1));
}


This is basically one method where you provide a standard option. There are two choice you have here: either put the implementation in one method and create an overload like this:

public static bool CheckSendNewEvent(DateTime now)
{
    // Implementation
}

public static bool CheckSendNewEvent()
{
    return CheckSendNewEvent(DateTime.Now);
}


Or use a default value. However since DateTime.Now is not a constant, you'll have to use a little trick:

public static bool CheckSendNewEvent(DateTime? now = null)
{
    now = now ?? DateTime.Now;
    // rest of method
}


public static DateTime Next(DateTime date, DayOfWeek dayOfWeek)


I'd name it GetNextWeekDay or something like that.

public static DateTime GetFirstMondayofMonth(DateTime now)
{
    var monday = new DateTime(now.Year, now.Month, 1);
    monday = Next(monday, DayOfWeek.Monday);
    return monday;
}


You can shorten this to

public static DateTime GetFirstMondayofMonth(DateTime now)
{
    return Next(new DateTime(now.Year, now.Month, 1), DayOfWeek.Monday);
}


Perhaps it's worth considering making Next an extension method?

const int SendTime = 8;


I don't know what that means from just looking at it. I'd suggest a comment // 8 am to avoid confusion.

Assert.AreEqual(false, checker);


Use the appropriate methods: Assert.IsFalse(checker) -- this way you don't throw away information that might help you diagnose a failed test.

Assert.AreEqual(testResult, firstMonday);


The first argument is the expected value, the second is the result.

The DateTime API is an external system, just like a database, the filesystem or a network operation. In unit testing these are typically stubbed out so you work with data entirely under your control. In your case this isn't a problem because the only DateTime used is the one you pass in. However should this not be the case, you should inject a proper datetime service which you can stub from your tests (if you're following along: this will be part of post 3 of my blogseries).

In (unit) testing there is the Arrange, Act, Assert approach to each test. I prefer to explicitly separate these parts with a newline and even a comment.

The naming of the tests.. I wouldn't put the [ExpectedResult] part as a DateTime since it just forces you to compare it to the [Scenario]. I think plain English "ShouldReturnSameDate" will be more effective.

Code Snippets

public bool CheckSendNewEvent()
{
    var now = DateTime.Now;
    const int SendTime = 8;
    var firstMonday = GetFirstMondayofMonth(now);
    var timeToSendOnFirstMonday = new DateTime(firstMonday.Year, firstMonday.Month, firstMonday.Day, SendTime, 0, 0);
    return now > timeToSendOnFirstMonday && now < (timeToSendOnFirstMonday.AddHours(1));
}

public static bool CheckSendNewEvent(DateTime now)
{
    const int SendTime = 8;
    var firstMonday = GetFirstMondayofMonth(now);
    var timeToSendOnFirstMonday = new DateTime(firstMonday.Year, firstMonday.Month, firstMonday.Day, SendTime, 0, 0);
    return now > timeToSendOnFirstMonday && now < (timeToSendOnFirstMonday.AddHours(1));
}
public static bool CheckSendNewEvent(DateTime now)
{
    // Implementation
}

public static bool CheckSendNewEvent()
{
    return CheckSendNewEvent(DateTime.Now);
}
public static bool CheckSendNewEvent(DateTime? now = null)
{
    now = now ?? DateTime.Now;
    // rest of method
}
public static DateTime Next(DateTime date, DayOfWeek dayOfWeek)
public static DateTime GetFirstMondayofMonth(DateTime now)
{
    var monday = new DateTime(now.Year, now.Month, 1);
    monday = Next(monday, DayOfWeek.Monday);
    return monday;
}

Context

StackExchange Code Review Q#85618, answer score: 4

Revisions (0)

No revisions yet.