【问题标题】:Moq Test - Mocked Service Call Always Returns NullMoq 测试 - 模拟服务调用始终返回 Null
【发布时间】:2020-02-10 19:32:37
【问题描述】:

总的来说,我是 Moq 和 Mocks/单元测试的新手。看了a video on Mocking which uses Moq 之后,我觉得我已经有了足够的了解,可以开始为我正在做的一个项目设置一些简单的测试。然而,再多的修改代码也无法帮助我通过第一次测试。

这是我的代码:

正在测试的接口

    public interface IDataInterface
    {
        Task<IList<T>> GetData<T>(string url);
        // Other stuff
    }

接口方法GetData的实现

        public async Task<IList<T>> GetData<T>(string url)
        {
            try
            {
                var json = await client.GetAsync(url).Result.Content.ReadAsStringAsync();
                var data = (JObject)JsonConvert.DeserializeObject(json);
                JArray arr = (JArray)data["resource"];
                return arr.ToObject<IList<T>>();
            }
            catch (InvalidCastException icEx)
            {
                throw new InvalidCastException("An error occurred when retrieving the data", icEx);
            }
            // Other catches
        }

服务调用实现接口GetData

        public async Task<IList<MyObj>> GetActiveObjs()
        {
            var data = await _myImplementedInterface.GetData<MyObj>(ActiveUrl);
            return data;
        }

我的测试

        [Fact]
        public async void MyImplementedInterface_GetActive_ReturnsDataOrEmptyList()
        {
            var _activeUrl = "http://some.url";
            using (var mock = AutoMock.GetLoose())
            {
                mock.Mock<IDataInterface>()
                    .Setup(x => x.GetData<MyObj>(_activeUrl))
                    .Returns(Task.FromResult(_SomeStaticDataRepresentation)));

                var svc = mock.Create<MyService>();

                var expected = _SomeStaticDataRepresentation;
                var actual = await svc.GetActiveObjs();

                Assert.True(actual != null);
                // Other assertions that never matter because of the null value of _actual_ variable
            }
        }

在早期,由于项目使用 Autofac 和 Moq,我遇到了一些问题,但我解决了这些具体问题。但是,我似乎无法超越从服务调用返回的空值。运行项目时,该方法返回数据,正如预期的那样,所以我对问题所在感到困惑。查看各种帖子和 Moq 快速入门并没有提供我自己解决这个问题所需的内容,所以我希望这里有人可以告诉我我做错了什么。我已经道歉,因为我确定这是一个新手错误。

【问题讨论】:

    标签: c# unit-testing moq


    【解决方案1】:

    首先解决实现问题。避免混合使用异步等待和阻塞调用,例如 Wait().Result,这可能会导致死锁。

    参考Async/Await - Best Practices in Asynchronous Programming

    public async Task<IList<T>> GetData<T>(string url) {
        try {
            var response = await client.GetAsync(url);
            var json = await response.Content.ReadAsStringAsync();
            var data = (JObject)JsonConvert.DeserializeObject(json);
            JArray arr = (JArray)data["resource"];
            return arr.ToObject<IList<T>>();
        } catch (InvalidCastException icEx) {
            throw new InvalidCastException("An error occurred when retrieving the data", icEx);
        }
        // Other catches
    }
    

    对于被测试的主题方法,如果不需要等待,则不需要使函数异步,只需返回Task

    public Task<IList<MyObj>> GetActiveObjs() {
        return _myImplementedInterface.GetData<MyObj>(ActiveUrl);
    }
    

    现在进行测试,因为已经在使用任务,所以测试应该是异步的,并且主题也在等待。

    [Fact]
    public async Task MyImplementedInterface_GetActive_ReturnsDataOrEmptyList() {
        using (var mock = AutoMock.GetLoose()) {
            //Arrange
            IList<MyObj> expected = _SomeStaticDataRepresentation;
            mock.Mock<IDataInterface>()
                .Setup(x => x.GetData<MyObj>(It.IsAny<string>()))
                .ReturnAsync(expected);
    
            var svc = mock.Create<MyService>();
    
            //Act
            var actual = await svc.GetActiveObjs();
    
            //Assert
            Assert.True(actual != null);
            Assert.True(actual == expected);
            // ...
        }
    }
    

    假设,根据显示的内容不确定活动 URL 是什么,可以在使用 It.IsAny&lt;string&gt;() 的测试中忽略它。

    【讨论】:

    • 谢谢;您建议的更改实际上解决了问题。具体来说,修复测试的部分似乎是It.IsAny&lt;string&gt;(),而不是使用硬编码变量_activeUrl
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多