简体   繁体   English

如何模拟从 Azure 函数调用的方法?

[英]How to mock methods that is called from Azure Function?

The problem of Azure Functions is that their Run function must be static. Azure Functions 的问题在于它们的 Run 函数必须是静态的。 This Run function calls a function that performs a database search query.此 Run 函数调用执行数据库搜索查询的函数。 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.我试图将方法分离成一个非静态类(比如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); 
        }

But it didn't quite do the job.但它并没有完全完成工作。 For this project, using Moq is a must.对于这个项目,必须使用 Moq。

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.实际实现会在调用时使用该函数,但在对函数进行隔离单元测试时可以用工厂方法替换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM