Thursday, 10 June 2010

Using Moq in unit tests

The unit test below demonstrates how we can use interfaces to moq implementations. In this case we want to make a unit test that tests a mail notification. Naturally we don't want to send a real mail every time we run the unit test, therefore it makes sense to create some interfaces in our application that enables us to test whether our send warning notification system works. It works by creating a property that implements an interface. Within our unit test we overwrite the property with a moq object that implements an interface hence the need for an interface. We then can configure the moq to return some predefined responses and assert whether the send mail method is called with the correct parameters

        [TestMethod]
        public void SendWarning_ToSubscribers_MessageIsSent()
        {
            //Arrange
            string Message =  "Test Message";
            NotifySubscribers target = new NotifySubscribers();
            Mock<ISubscribers> subscribersMoq = new Mock<ISubscribers>();
            target.Subscribers = subscribersMoq.Object;
            subscribersMoq.Setup(i => i.Get()).Returns(() => new List<string> { "nigel.findlater@partnerre.com" });
            Mock<INotify> notifyMoq = new Mock<INotify>();
            target.EmailNotifier = notifyMoq.Object;
            notifyMoq.Setup(n => n.SendMail(
                It.IsAny<string>(),
                It.IsAny<string>(),
                It.IsAny<string>(),
                It.Is<string>(s => s.Equals(Message)),
                Message
                ));

            //Act
            target.SendWarning(Message);
            //Assert
            subscribersMoq.VerifyAll();
            notifyMoq.VerifyAll();

        }

Here is the class that we are testing. Notice that we have made 2 public properties that are of the interface type INotify and ISubscribers. These properties are instantiated in the constructor but can be overwritten by moq thus making it possible to test this class without sending out any mails

namespace Ccp.Notification
{
    public class NotifySubscribers : INotifySubscribers
    {
        public INotify EmailNotifier { get; set; }
        public ISubscribers Subscribers { get; set; }

        public NotifySubscribers()
        {
            this.Subscribers = new Subscribers();
            this.EmailNotifier = new NotifyEmail();
        }

        public void SendWarning(string WarningMessage)
        {
            if (Subscribers == null)
            {
                throw new InvalidOperationException("Subscriber implementation not injected");
            }

            foreach(var email in Subscribers.Get())
            {
                this.EmailNotifier.SendMail(email, email, "", WarningMessage, WarningMessage);
            }
        }
    }
}

namespace Ccp.Infrastructure
{
    public interface ISubscribers
    {
        List<string> Get();
    }
}

namespace Ccp.Infrastructure
{
    public interface INotifySubscribers
    {
        void SendWarning(string warningMessage);
    }
}

Here is the implementation of ISubscribers that is not a part of this test

namespace Ccp.Infrastructure
{
    public class Subscribers: ISubscribers
    {
        public List<string> Get()
        {
            ObjectContext objectContext = new CatFocusEntities(Ccp.Infrastructure.Configuration.CatFocusEntitiesConnectionString);
            IDatabaseContext databaseContext = new DatabaseContext(objectContext);
            var Emails = from no in databaseContext.Query<SystemMonitorNotification>()
                         join u in databaseContext.Query<User>()
                         on no.UserId equals u.Id
                         select u.EMail ;

            return Emails.ToList();
        }
    }
}