Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

First Unit Test (VS2010 C#)

This is my first encounter with unit testing and I am trying to understand how can this concept be used on a simple date validation.

The user can select a ToDate that represents the date until a payment can be made. If our date is not valid the payment cant be made.

    private void CheckToDate(DateTime ToDate)
    {
        if (Manager.MaxToDate < ToDate.Year)
            //show a custom message
    }

How can unit tests be used in this case?

Regards,

Alex

Thanks for your answers:

As suggested by many of you I will split the function and separate the validation from the message display and use unit tests just for this.

public bool IsDateValid(DateTime toDate)
{
    return (Manager.MaxToDate < toDate.Year);
}
like image 367
thedev Avatar asked May 03 '26 04:05

thedev


2 Answers

Yes it is possible. But unit testing changes design of your class. To make possible unit testing of this code, you should made following changes:

  1. Make your method public. (It is possible to make it protected, but for simplicity make it public).

  2. Extract all external dependencies of this method to interface, so you can mock them. Then you can use some mocking library (moq, Rhino.Mocks) to simulate real dependencies and write asserts.

  3. Write test.

Here is sample code.

The class under test:

public class ClassUnderTest
{
    public IManager Manager {get;set;}
    public IMessanger Messanger {get;set}

    public  ClassUnderTest (IManager manager, IMessanger messanger)
    {
        Manager = manager;
        Messanger = messanger;
    }

    private void CheckToDate(DateTime ToDate)
    {
        if (Manager.MaxToDate < ToDate.Year)
            //show a custom message
            Messanger.ShowMessage('message');
    }
}

Test:

[TestFixture]
public class Tester
{
    public void MessageIsShownWhenDateIsLowerThanMaxDate()
    {
        //SetUp
        var manager = new Mock<IManager>();
        var messanger = new Mock<IMessanger>();

        var maxDate = DateTime.Now;

        manager.Setup(m => m.MaxToDate).Returns(maxDate);

        var cut = new ClassUnderTest (manager.Object, messanger.Object);

        //Act
        cut.CheckToDate();

        //Assert
        messanger.Verify(foo => foo.ShowMessage("message"), Times.AtLeastOnce())
    }
}

Design change, introduced by test gives you nice decoupling in system. And tests could be written for specific classes, when external dependencies are event not written.

like image 51
gor Avatar answered May 05 '26 18:05

gor


Sure thing :-) Detecting that the custom message is shown can require a little trick (I assume you mean a messagebox displayed on a GUI, but the idea is the same even if the message is displayed differently).

You can't detect mssage boxes from unit tests, neither you want to launch the whole GUI environment from your unit tests. The easiest way to work around this is to hide the actual code displaying a message box in a separate method, ideally in a distinct interface. Then you can inject a mock implementation of this interface for your unit tests. This mock does not display anything, just records the message passed to it, so you can check it in your unit test.

The other issue is that your method is private. Check first where it is called from, and whether it can be called via a public method without too much complication. If not, you may need to make it (temporarily) public to enable unit testing. Note that the need to unit test private methods is usually a design smell: your class may be trying to do too much, taking on too many distinct responsibilities. You may be able to extract some of its functionality into a distinct class, where it becomes public, thus directly unit testable. But first you need to have those unit tests, to ensure you are not breaking anything when refactoring.

You then need to set up the Manager.MaxToDate prior to the test with a suitable date, and call CheckToDate with various parameters, check that the result is as expected.

The recommended reading for similar tricks and more is Working Effectively with Legacy Code.

like image 32
Péter Török Avatar answered May 05 '26 17:05

Péter Török