如何模拟从 Azure Function 调用的方法?
How to mock methods that is called from Azure Function?
Azure Functions 的问题是它们的 运行 函数必须是静态的。此 运行 函数调用一个执行数据库搜索查询的函数。我很想模拟这个功能
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);
}
然而,对此的模拟尝试失败了。测试本身 运行,但它不是 运行 模拟版本,它只是 运行 使用互联网连接的原始版本。
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);
}
我试图将方法分离成一个非静态的 class(比方说 SomethingTool)并实现类似的东西。
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);
}
但它并没有完全完成工作。对于这个项目,使用Moq是必须的。
最简单的方法是重构函数以抽象出依赖关系,以便在测试时可以根据需要替换它们
例如
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);
}
}
现在可以这样测试了
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);
}
}
实际实现会在调用时使用该函数,但在对函数进行隔离单元测试时可以用工厂方法代替。
Azure Functions 的问题是它们的 运行 函数必须是静态的。此 运行 函数调用一个执行数据库搜索查询的函数。我很想模拟这个功能
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);
}
然而,对此的模拟尝试失败了。测试本身 运行,但它不是 运行 模拟版本,它只是 运行 使用互联网连接的原始版本。
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);
}
我试图将方法分离成一个非静态的 class(比方说 SomethingTool)并实现类似的东西。
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);
}
但它并没有完全完成工作。对于这个项目,使用Moq是必须的。
最简单的方法是重构函数以抽象出依赖关系,以便在测试时可以根据需要替换它们
例如
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);
}
}
现在可以这样测试了
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);
}
}
实际实现会在调用时使用该函数,但在对函数进行隔离单元测试时可以用工厂方法代替。