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

时间:2019-02-26 15:54:25

标签: c# moq

Azure函数的问题在于它们的Run函数必须是静态的。该运行函数调用执行数据库搜索查询的函数。我很想模拟这个功能

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); 
        }

但是,对此的模拟尝试失败。该测试本身已经运行,但是它没有运行模拟版本,只是运行了使用Internet连接的原始版本。

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);
        }

我试图将方法分为一个非静态类(比如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。

1 个答案:

答案 0 :(得分:2)

最简单的方法是重构功能以抽象出依赖项,以便在测试时可以根据需要替换它们

例如

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);
    }
}

实际的实现将在调用时使用该函数,但是当单独对函数进行单元测试时,可以使用工厂方法代替。