2019年1月22日 星期二

[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







沒有留言:

張貼留言