Moq 4 and “LINQ to Mocks”

“If the code samples are harder to follow please visit my blog https://blog.rajsoftware.com/post/2011/06/07/Moq-4-and-e2809cLINQ-to-Mockse2809d.aspx

While searching for Moq code samples, I came across that Moq 4 was released few months ago. The key improvement was the new “LINQ to Mocks”.

This post demonstrates few examples of the usage of Mocks and LINQ queries. For each example, we stub out dependencies using lambda expressions first, and then see the corresponding LINQ version. At the end we see the performance of each Unit Tests.

Note: I’m using the xUnit Testing Framework. However you can apply the same principles to other Unit testing frameworks.

 

Single Stub

Lambdas:

 1: [Fact]

 

 2: public void UpdateCustomer_WhenCustomerIsNotUpdated_ReturnsFalse()

 

 3: {

 

 4:     //Arrange

 

 5:     var dbServiceStub = new Mock<IDbService>();

 

 6:     dbServiceStub.Setup(d => d.Update(It.IsAny<Customer>())).Returns(false);

 

 7:     var customerService = new CustomerService();

 

 8:     customerService.DbService = dbServiceStub.Object;

 

 9:

 

 10:     //Act

 

 11:     bool isUpdated = customerService.Update(It.IsAny<Customer>());

 

 12:

 

 13:     //Assert

 

 14:     Assert.False(isUpdated);

 

 15: }

 

LINQ:

 1: [Fact]

 

 2:  public void UpdateCustomer_WhenCustomerIsNotUpdated_ReturnsFalse()

 

 3:  {

 

 4:      //Arrange

 

 5:      IDbService dbServiceStub = (from dbService in Mocks.Of<IDbService>() where dbService.Update(It.IsAny<Customer>()) == false

 

 6:                                  select dbService).First();

 

 7:      var customerService = new CustomerService { DbService = dbServiceStub };

 

 8:

 

 9:      //Act

 

 10:      bool isUpdated = customerService.Update(It.IsAny<Customer>());

 

 11:

 

 12:      //Assert

 

 13:      Assert.False(isUpdated);

 

 14:  }

 

 

Multiple Stubs

Lambdas:

 1: [Fact]

 

 2: public void UpdateCustomer_WhenCustomerIsUpdated_ReturnsTrue()

 

 3: {

 

 4:     //Arrange

 

 5:     var dbServiceStub = new Mock<IDbService>();

 

 6:     dbServiceStub.Setup(d => d.Update(It.IsAny<Customer>())).Returns(true);

 

 7:     var loggerServiceStub = new Mock<ILoggerService>();

 

 8:

 

 9:     var customerService = new CustomerService { DbService = dbServiceStub.Object, LogService = loggerServiceStub.Object };

 

 10:

 

 11:     //Act

 

 12:     bool isUpdated = customerService.Update(It.IsAny<Customer>());

 

 13:

 

 14:     //Assert

 

 15:     Assert.True(isUpdated);

 

 16: }

 

 

LINQ:

 1: [Fact]

 

 2: public void UpdateCustomer_WhenCustomerIsUpdated_ReturnsTrue()

 

 3: {

 

 4:     //Arrange

 

 5:     var fakes = (from dbService in Mocks.Of<IDbService>()

 

 6:                  from loggerService in Mocks.Of<ILoggerService>()

 

 7:                  where dbService.Update(It.IsAny<Customer>()) == true

 

 8:                  select new { dbServiceStub = dbService, loggerServiceStub = loggerService }).First();

 

 9:

 

 10:     var customerService = new CustomerService { DbService = fakes.dbServiceStub, LogService = fakes.loggerServiceStub };

 

 11:

 

 12:     //Act

 

 13:     bool isUpdated = customerService.Update(It.IsAny<Customer>());

 

 14:

 

 15:     //Assert

 

 16:     Assert.True(isUpdated);

 

 17: }

 

 

 

Mocks and Stubs

 

Lambdas:

 1: [Fact]

 

 2: public void UpdateCustomer_WhenCustomerIsUpdated_VerifyLoggerServiceLogIsCalled()

 

 3: {

 

 4:     //Arrange

 

 5:     var dbServiceStub = new Mock<IDbService>();

 

 6:     dbServiceStub.Setup(d => d.Update(It.IsAny<Customer>())).Returns(true);

 

 7:     var loggerServiceMock = new Mock<ILoggerService>(); //We verify against the Mock

 

 8:     loggerServiceMock.Setup(l => l.Log(It.IsAny<string>())).Verifiable();

 

 9:

 

 10:     var customerService = new CustomerService()

 

 11:     {

 

 12:         DbService = dbServiceStub.Object,

 

 13:         LogService = loggerServiceMock.Object

 

 14:     };

 

 15:

 

 16:     //Act

 

 17:     customerService.Update(It.IsAny<Customer>());

 

 18:

 

 19:     //Assert

 

 20:     Mock.Get(loggerServiceMock.Object).Verify(c => c.Log(It.IsAny<string>()));

 

 21: }

 

 

LINQ:

 1: [Fact]

 

 2: public void UpdateCustomer_WhenCustomerIsUpdated_VerifyLoggerServiceLogIsCalled()

 

 3: {

 

 4:     //Arrange

 

 5:     var fakes = (from dbService in Mocks.Of<IDbService>()

 

 6:                  from loggerService in Mocks.Of<ILoggerService>()

 

 7:                  where dbService.Update(It.IsAny<Customer>()) == true

 

 8:                  select new { dbServiceStub = dbService, loggerServiceMock = loggerService }).First();

 

 9:

 

 10:     var customerService = new CustomerService { DbService = fakes.dbServiceStub, LogService = fakes.loggerServiceMock };

 

 11:

 

 12:     //Act

 

 13:     bool isSend = customerService.Update(It.IsAny<Customer>());

 

 14:

 

 15:     //Assert

 

 16:     Mock.Get(fakes.loggerServiceMock).Verify(c => c.Log(It.IsAny<string>()));

 

 17: }

 

 

Testing an MVC Action Filter

 

Lambdas:

 1: [Fact]

 

 2: public void OnActionExecuted_WhenEmployeeSalaryIsEqualToZero_ EnsureActionExecutedContextResultEqualToFilterResult()

 

 3: {

 

 4:     //Arrange

 

 5:     decimal employeeUnpaidAmount = 0.0M;

 

 6:     var employeeServiceStub = new Mock<IEmployeeService>();

 

 7:     employeeServiceStub.Setup(s => s.GetSalary()).Returns(employeeUnpaidAmount);

 

 8:

 

 9:     var filter = new EmployeeSalaryNotificationAttribute

 

 10:     {

 

 11:         EmployeeService = employeeServiceStub.Object

 

 12:     };

 

 13:

 

 14:     var actionExecutedContextMock = new Mock<ActionExecutedContext>();

 

 15:     var routeData = new RouteData();

 

 16:     routeData.Values.Add("fakeIdKey", "fakeIdValue");

 

 17:     actionExecutedContextMock.SetupGet(r => r.RouteData).Returns(routeData);

 

 18:

 

 19:     var request = new Mock<HttpRequestBase>();

 

 20:     var httpContext = new Mock<HttpContextBase>();

 

 21:     httpContext.SetupGet(c => c.Request).Returns(request.Object);

 

 22:     actionExecutedContextMock.SetupGet(h => h.HttpContext).Returns(httpContext.Object);

 

 23:

 

 24:     //Act

 

 25:     filter.OnActionExecuted(actionExecutedContextMock.Object);

 

 26:

 

 27:     //Assert

 

 28:     Assert.Equal((actionExecutedContextMock.Object.Result as ContentResult).Content, filter.SalaryResult);

 

 29: }

 

 

LINQ:

 1: [Fact]

 

 2: public void OnActionExecuted_WhenEmployeeSalaryIsEqualToZero_EnsureActionExecutedContextResultEqualToFilterResult()

 

 3: {

 

 4:     //Arrange

 

 5:     RouteData routeData = new RouteData();

 

 6:     routeData.Values.Add("fakeIdKey", "fakeIdValue");

 

 7:

 

 8:     var fakes = (from employeeService in Mocks.Of<IEmployeeService>()

 

 9:                  from actionExecutedContext in Mocks.Of<ActionExecutedContext>()

 

 10:                  where employeeService.GetSalary() == 0.00M &&

 

 11:                  actionExecutedContext.HttpContext == Mock.Of<HttpContextBase>() &&

 

 12:                  actionExecutedContext.HttpContext.Request == Mock.Of<HttpRequestBase>() &&

 

 13:                  actionExecutedContext.RouteData == new RouteData()

 

 14:                  select new { EmployeeServiceStub = employeeService, ActionExecutedContextMock = actionExecutedContext })

 

 15:                  .First();

 

 16:

 

 17:     var filter = new EmployeeSalaryNotificationAttribute

 

 18:     {

 

 19:         EmployeeService = fakes.EmployeeServiceStub

 

 20:     };

 

 21:

 

 22:     //Act

 

 23:     filter.OnActionExecuted(fakes.ActionExecutedContextMock);

 

 24:

 

 25:     //Assert

 

 26:     Assert.Equal((fakes.ActionExecutedContextMock.Result as ContentResult).Content, filter.SalaryResult);

 

 27: }

 

 

Key things to notice:

– The tests with LINQ queries reflect the test scenarios/conditions in a more of a specification style. This improves the tests readability.

 

– The query returns an infinite number of mocks. Typically we access the first element.

   var fakes = (LINQ query).First();

 

– LINQ query result returns real object(s) and not the type Mock<T>. So we do not need to use the EmployeeServiceStub.Object. Instead we can just use the returned element.

   EmployeeService = fakes.EmployeeServiceStub;

 

– When you have multiple stubs or mocks, you can return all of them using an anonymous type.

   select new { dbServiceStub = dbService, loggerServiceStub = loggerService }));

 

– Not used in these code samples, but if you are using the MockFactory class, it is now absolute in v4. MockFactory will be retired in v5.

 

Performances:

Here is a very quick benchmark results on each Unit Test.

Unit Test Lambda version LINQ version
UpdateCustomer_WhenCustomerIsNotUpdated_ReturnsFalse 0.95s 1.01s
UpdateCustomer_WhenCustomerIsUpdated_ReturnsTrue 0.97s 1.06s
UpdateCustomer_WhenCustomerIsUpdated

_VerifyLoggerServiceLogIsCalled

0.94s 1.07s
OnActionExecuted_WhenEmployeeSalaryIsEqualToZero

_EnsureFilterResultContainsTheStringNotPaid

1.08s 1.29s

 

Unit Tests with LINQ queries take “tiny” bit longer than the Lambda counterparts. However, I would personally still use LINQ version as it improves the readability of Unit Tests.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s