Raj Aththanayake's Blog Raj Aththanayake's Blog | June 2011

Moq 4 and “LINQ to Mocks”

7. June 2011

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.

Test

Lambda

LINQ

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.

Unit Testing

ASP.NET MVC 3 Model Metadata Providers

5. June 2011

One of the cool features of ASP.NET MVC framework is the ability provide Model's metadata using DataAnnotation attributes. Below is a comprehensive example on how Model Metadata Providers behave using the new ASP.NET MVC 3 Display DataAnnotation attribute as an example.

Please refer to my post below.

http://www.dotnetcurry.com/ShowArticle.aspx?ID=715

16/6/2011 - Nice to see this post hit the front page of http://asp.net/mvc

ASP.NET / ASP.NET MVC