C#- Mock protected async method using Moq

C#- Mock protected async method using Moq

Mocking is a powerful technique in unit testing that allows us to create mock objects based on interfaces or partial mocks of classes. In this blog post, we will explore some advanced features of the Moq framework, including mocking protected methods and async methods. We’ll provide a step-by-step guide and real-world examples to demonstrate these concepts. So, let’s dive in!

Why Mocking?

Traditionally, Moq is used to create mock objects based on interfaces. However, Moq also allows us to create partial mocks of classes. Partial mocking is useful when we want a class to behave as usual but need to override certain functionality for testing purposes.

What is a Partial Mock?

Partial mocking refers to the technique of taking a class and instructing it to behave normally, except for specific overridden functionality. This allows us to isolate and test specific parts of the class while keeping the rest intact.

Example:

To demonstrate mocking protected methods and async methods, let’s consider a scenario involving a ServiceHelper class:

public class ServiceHelper
{
	public async Task<string> GetData(string url)
	{
		var result = await SendRequest(url);
		Console.WriteLine("Doing some real work");
		return result;
	}
	protected virtual async Task<string> SendRequest(string url)
	{
		Console.WriteLine($"Sending Request to {url}");
		var result = await Task.FromResult("From Protected Method");
		return result;
	}
}

We’ll write a unit test for the public method GetData:

public class ServiceHelperTest
{
	[Fact]
	public async Task Should_call_protected_method()
	{
		var p = new ServiceHelper();
		var data = await p.GetData("https://jsonplaceholder.typicode.com/todos/1");
		Assert.Contains(data,"From Protected Method");
	}
}

The test is calling the actual protected method. Now, let’s see how to mock the protected method using Moq.

Let’s create a mock of the class and set up the behavior. IntelliSense may not show the protected method during the setup process. If this happens, don’t worry. We can still proceed with running the test without explicitly setting up the behavior and observe the result.

     [Fact]
	public async Task Should_throw_error_if_call_on_mock_object()
	{
		var mockService = new Mock<ServiceHelper>();
		var data = await mockService.Object.GetData("https://jsonplaceholder.typicode.com/todos/1");
		Assert.Contains(data, "From Protected Method");
	}


When running the test without setting up the behavior of the mock object, you may encounter an error similar to the following:

[FAIL] ServiceHelperTest.Should_throw_error_if_call_on_mock_object: 
Value cannot be null. (Parameter 'value')

This error indicates that the mock object’s method call resulted in a null value being passed as a parameter. It is essential to configure the mock’s behavior to return a valid value for the expected method call.

To resolve this issue, you need to set up the behavior of the protected method using the appropriate setup method provided by the mocking framework. By configuring the mock’s behavior, you ensure that it returns the expected value when the protected method is invoked.

How to Mock the Protected Method:

To mock the protected method, we need to import the Moq.Protected namespace:

using Moq.Protected;

Next, we can modify our unit test to mock the protected method:
Next, we can modify our unit test to mock the protected method:

   [Fact]
	public async Task Should_call_mock_method()
	{
		var mockService = new Mock<ServiceHelper>();
		mockService.Protected().Setup<Task<string>>("SendRequest", ItExpr.IsAny<string>()).ReturnsAsync(() => "From Mock")
			.Verifiable();
		var result = await mockService.Object.GetData("https://jsonplaceholder.typicode.com/todos/1");
		Assert.Contains(result,"From Mock");
		mockService.Verify();
	}

In the above code, we create a mock object of the ServiceHelper class and use the Protected() method to access the protected method SendRequest. We then set up the behavior of the mocked method using Setup. Finally, we can verify that the method was called using Verify.

Limitations:

It’s important to note a couple of limitations when working with the Moq framework:

  • IntelliSense may not be available when setting up the mock for the protected method. This is a drawback of the API.
  • When setting up an IProtectedMock, use Moq.Protected.ItExpr instead of Moq.It.

Conclusion

Mockingprotected methods and async methods is a valuable skill in unit testing with the Moq framework. By leveraging partial mocking and the advanced features provided by Moq, we can effectively isolate and test specific parts of our code. In this blog post, we covered the basics of mocking, demonstrated how to

Related article

How to mock HttpClient-C#

Next Post Previous Post
No Comment
Add Comment
comment url