Tuesday, January 22, 2019

[moq] Mock object and Mock.of


 C#   Unit test   Moq


▌Introduction


Here are three basic ways to use Moq in unit test.
1.  Mock instance
2.  Mock.of
3.  Mock.of (Setup in lambda)

▌Environment


▋Visual Studio 2017 community
▋dotnet core 2.2.101
▋Moq 4.10.1


▌Implement


We will test the GetAge(…) function of class, BirthdayRepository. It has some dependencies inside as following,

l   IDataAccessService: responsible for fetching someone’s birthday from database
l   ILogger: Logger


▋Interfaces and Classes

▋BirthdayRespository.cs

public class BirthdayRepository : IBirthdayRepository
    {
        private IDataAccessService<Birthday> _dataAccess =null;
        private ILogger _logger = null;
        
        public BirthdayRepository(
            IDataAccessService<Birthday> dataAccess,
            ILogger logger
        )
        {
            if(dataAccess!=null) this._dataAccess = dataAccess;
            if(logger!=null) this._logger = logger;
        }

        public int GetAge(string idNumber)
        {
            Birthday birthday = this._dataAccess.Get(idNumber);
            int age = DateTime.Now.Year - birthday.Year;
            this._logger.Info($"{idNumber}'s age is {age.ToString()}");
            return age;
        }

        public void Dispose()
        {

        }
    }

▋IBirthdayRespository.cs

public interface IBirthdayRepository : IDisposable
{
        int GetAge(string idNumber);
}


▋IDataAccessService

public interface IDataAccessService<T>
    {
        string ConnectionStr { get; set; }
        T Get(string id);
    }



▋ILogger

public interface ILogger
    {
        void Info(string msg);
    }


▋Unit test by Mock instance

const int targetYear = 2001;
var birthday = new Birthday() {
       Year = targetYear,
       Month = 10,
       Day = 18
};

 int expected = DateTime.Now.Year - targetYear;
 int actual = 0;

 #region Mock instance
 var mockLogger = new Mock<ILogger>();
var mockDataAccess = new Mock<IDataAccessService<Birthday>>();
mockDataAccess.SetupProperty(s => s.ConnectionStr);
mockDataAccess.Object.ConnectionStr = string.Empty;
mockDataAccess.Setup(x => x.Get(It.IsAny<string>())).Returns(birthday);
IBirthdayRepository birthdayRepository = new BirthdayRepository(mockDataAccess.Object, mockLogger.Object);
actual = birthdayRepository.GetAge("YYYYYY");
mockDataAccess.Verify(x => x.Get(It.IsAny<string>()), Times.Once);
#endregion

Assert.AreEqual(expected, actual);




▋Unit test by Mock.of

We can replace the codes in region with Mock.of

#region Mock.of
var mockLogger = Mock.Of<ILogger>();
var mockDataAccess = Mock.Of<IDataAccessService<Birthday>>();
mockDataAccess.ConnectionStr = string.Empty;
Mock.Get(mockDataAccess).Setup(x => x.Get(It.IsAny<string>())).Returns(birthday);

IBirthdayRepository birthdayRepository = new BirthdayRepository(mockDataAccess, mockLogger);
 actual = birthdayRepository.GetAge("YYYYYY");
 #endregion



▋Unit test by Mock.of (Setup in lambda)

Or even graceful,

#region Mock.of (Setup in lambda)
var mockLogger = Mock.Of<ILogger>();
var mockDataAccess = Mock.Of<IDataAccessService<Birthday>>(x => x.ConnectionStr == string.Empty && x.Get(It.IsAny<string>()) == birthday);

IBirthdayRepository birthdayRepository = new BirthdayRepository(mockDataAccess, mockLogger);
actual = birthdayRepository.GetAge("YYYYYY");
#endregion



▌Reference







No comments:

Post a Comment