3

Working on a event scheduler with TDD and writing test project for the below class.

Decided to write a test methods for Constructor logic

public class TechDay
{
    public Session MorningSlot { get; set; }
    public Session EveningSlot { get; set; }

    public TechDay()
    {
        this.MorningSlot = new Slot();
        this.EveningSlot = new Slot();

        this.MorningSlot.Sessions= new List<Session>();
        this.EveningSlot.Sessions= new List<Session>();
        this.ConfigureEventSettings();
    }

    protected virtual void ConfigureEventSettings()
    { 
      CultureInfo provider = CultureInfo.InvariantCulture;
      this.MorningSlot.StartTime = DateTime.ParseExact("9:00 AM", "h:mm tt", provider);
      this.MorningSlot.EndTime = DateTime.ParseExact("12:00 PM", "h:mm tt", provider);
      this.EveningSlot.StartTime = DateTime.ParseExact("1:00 PM", "h:mm tt", provider);
      this.EveningSlot.EndTime = DateTime.ParseExact("5:00 PM", "h:mm tt", provider);
    }
}

Test Methods

[TestMethod]
public void CheckMorningSlot()
{
    TechDay techday=new TechDay();
    Assert.IsNotNull(techday.MorningSlot);
}

[TestMethod]
public void CheckEveningSlot()
{
    TechDay techday=new TechDay();
    Assert.IsNotNull(techday.EveningSlot);
}

[TestMethod]
public void CheckEveningSlotSessions()
{
    TechDay techday=new TechDay();
    Assert.IsNotNull(techday.EveningSlot.Sessions);
}

[TestMethod]
public void CheckMorningSlotSessions()
{
    TechDay techday=new TechDay();
    Assert.IsNotNull(techday.MorningSlot.Sessions);
}

Do I need to write different methods to check different parameter initialization in a constructor? Also not that Constructor calls another method.

What is the best way of writing the test methods for this code?

Billa
  • 5,226
  • 23
  • 61
  • 105
  • 8
    Virtual method call in constructor is not good idea. – Tilak Apr 02 '13 at 06:32
  • @Tilak, I just made that method as virtual, because other conf event also can inherit the TechDay and change the start & end time. Ex: TechNights. What could be the best suggesstion? – Billa Apr 02 '13 at 06:34
  • Billa, if you can correctly recall order of calls between base constructor, derived constructor and virtual methods from inside a constructor and what fields will/will not be initialized at each call than it is probably ok. – Alexei Levenkov Apr 02 '13 at 06:50
  • @AlexeiLevenkov, i changed it to `private void` and removed `virtual` – Billa Apr 02 '13 at 08:16

2 Answers2

2

You should be testing the functional requirements of your code rather than each bit of code. So what is the functionality that you are testing? If there is a requirement that the morning slot starts at 9am then your test would be something like:

[TestMethod]
public void Morning_slot_starts_at_nine_am()
{
    var expected = DateTime.ParseExact("9:00 AM", "h:mm tt", CultureInfo.InvariantCulture);
    var techDay = new TechDay();
    var actual = techDay.MorningSlot.StartTime;
    Assert.AreEqual(expected, actual);
}
Andy Nichols
  • 2,952
  • 2
  • 20
  • 36
  • Looks fine, How do i check a special event that falls anytime between 3-4 P.M, with Assert – Billa Apr 02 '13 at 09:18
  • @Billa, it's unusual that a requirement would be that imprecise, the time would generally follow a rule, and you would test that rule produces the right result. But if that is really what you need to do then I would expect to see something in the test that sets a boolean value showing whether the time is between 3 and 4 pm, then Assert.IsTrue(isBetweenThreeAndFourPm); – Andy Nichols Apr 02 '13 at 09:21
  • 1
    +1. Note - there is no need to use `Parse` - constructing DateTime directly from hours/minutes would be more compact and less error prone due to type checking. Consider if using `TimeSpan` looks better if `DateTime` value does not includes portion itself... – Alexei Levenkov Apr 02 '13 at 16:32
1

You must extract configuration logic to another class. Use interfaces to mock (see Moq). And you will get simple tests.

public class TechDay
{
    public Session MorningSlot { get; set; }
    public Session EveningSlot { get; set; }

    public TechDay(IEventConfigurator morningConfigurator, IEventConfigurator eveningConfigurator)
    {
        MorningSlot = new Session();
        morningConfigurator.Configure(MorningSlot);

        EveningSlot = new Session();
        eveningConfigurator.Configure(EveningSlot);
    }
}

public interface IEventConfigurator
{
    void Configure(Session session);
}

public class Session
{
    public static DateTime StartTime { get; set; }
    public static DateTime EndTime { get; set; }
}

public class FromStringEventConfigurator : IEventConfigurator
{
    private readonly string _begin;
    private readonly string _end;

    public FromStringEventConfigurator(string begin, string end)
    {
        _begin = begin;
        _end = end;
    }

    public void Configure(Session session)
    {
        CultureInfo provider = CultureInfo.InvariantCulture;
        Session.StartTime = DateTime.ParseExact(_begin, "h:mm tt", provider);
        Session.EndTime = DateTime.ParseExact(_end, "h:mm tt", provider);
        // ...
    }
}
SeeSharp
  • 1,730
  • 11
  • 31