Reputation: 450
The problem of Azure Functions is that their Run function must be static. This Run function calls a function that performs a database search query. I would love to mock this function
namespace Something.App{
public class Something {
[FunctionName("Something")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
ILogger log)
{
//perform something
dbCall(); // I wish to mock
//perform something
return new OkObjectResult(result);
}
However, mocking attempts at this has failed. The test itself ran, but it doesn't run the mocked version, it just run the original version which uses internet connection.
namespace Something.Test{
public class SomethingTest{
private readonly ILogger logger = TestFactory.CreateLogger();
private Mock<Something> CreateMockObject(){
var mock = new Mock<Something>();
mock.SetupSequence(f => f.dbCall()).Returns(something);
return mock;
}
[Fact]
public async void Http_Respond_On_Valid_Data()
{
CreateMockObject();
Dictionary<string,StringValues> postParam= new Dictionary<string,StringValues>();
postParam.Add("param", "value");
var request = new DefaultHttpRequest(new DefaultHttpContext()){
Query = new QueryCollection(postParam)
};
var response = (OkObjectResult)await Something.Run(request, logger);
string stringResponse = (String) response.Value;
Assert.Equal("XKCD", stringResponse);
}
I have tried to separate the method into a non static class (let's say SomethingTool) and achieve something like this.
namespace Something.App{
public class Something {
[FunctionName("Something")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
ILogger log)
{
SomethingTool object = new SomethingTool();
//perform something
object.dbCall(); // I wish to mock
//perform something
return new OkObjectResult(result);
}
But it didn't quite do the job. For this project, using Moq is a must.
Upvotes: 4
Views: 3589
Reputation: 247153
The easiest approach would be to refactor the function to abstract out the dependencies so that they can be replaced as needed when testing
For example
public static class Something {
public static Func<ISomeDependency> Factory = () => return new SomeDependency();
[FunctionName("Something")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
ILogger log) {
//...
ISomeDependency tool = Factory.Invoke();
var result = await tool.dbCall();
//...
return new OkObjectResult(result);
}
}
Which can now be tested like
public class SomethingTest{
private readonly ILogger logger = TestFactory.CreateLogger();
[Fact]
public async Task Http_Respond_On_Valid_Data() {
//Arrange
var expected = "XKCD";
var mock = new Mock<ISomeDependency>();
mock.Setup(_ => _.dbCall()).ReturnsAsync(expected);
Something.Factory = () => return mock.Object; //<-- replace factory delegate
var postParam = new Dictionary<string, StringValues>();
postParam.Add("param", "value");
var request = new DefaultHttpRequest(new DefaultHttpContext()){
Query = new QueryCollection(postParam)
};
//Act
var response = (OkObjectResult)await Something.Run(request, logger);
string actual = (String) response.Value;
//Assert
Assert.Equal(expected, actual);
}
}
The actual implementation will use the function when invoked, but with the factory method can be replaced when unit testing the function in isolation.
Upvotes: 3