简体   繁体   English

返回 IEnumerable 类型的 Mocking 方法

[英]Mocking methods that return IEnumerable types

I am running into this issue in a somewhat larger context, but when condensed to the bare minimum, the question that remains is why does Moq not return the type specified in the interface for mocked methods?我在更大的上下文中遇到了这个问题,但是当浓缩到最低限度时,剩下的问题是为什么 Moq 不返回接口中为模拟方法指定的类型? IEnumerable and List come back as empty arrays, When I specifically call Setup with a return value, it changes, at least in the example below. IEnumerable 和 List 返回为空 arrays,当我专门用返回值调用 Setup 时,它至少在下面的示例中会发生变化。

    public interface ITestTarget    {
        public IEnumerable<int> getSomeData();
    }

    public class TestTarget : ITestTarget    {
        public List<int> getSomeData() {return new List<int>() { 1 };  }
    }

    public class MockTest     {
        [Fact]
        public void TestMe()
        {
            var testMock = new Mock<ITestTarget>();
            var someResult = testMock.Object.getSomeData();

            Assert.IsType<Int32[]>(someResult);    // Why does this pass? someResult is an Integer array!

            testMock.Setup(m => m.getSomeData()).Returns(new List<int> { });   // forcing it to a list

            someResult = testMock.Object.getSomeData();

            Assert.IsType<List<int>>(someResult);    // Now it is a list
        }
    }

My real issue is that Moq seems to return an empty array even when I specifically set it up with an empty List (of a complex type), but I will ask that question later.我真正的问题是 Moq 似乎返回一个空数组,即使我专门用一个空列表(复杂类型)设置它,但我稍后会问这个问题。

Update and Re-phrasing my question更新并重新表述我的问题

I had not considered the fact that an array IS an IEnumerable, my Interface has IEnumerable, and that therefore what Moq returns is not wrong.我没有考虑到数组是 IEnumerable 的事实,我的接口具有 IEnumerable,因此 Moq 返回的内容没有错。 When I change the interface to List, the Mock returns a List.当我将接口更改为 List 时,Mock 返回一个 List。

I am not ready to change the return types in my code.我还没准备好更改代码中的返回类型。 I can custom-tweak my assertions to deal with either type, but:我可以自定义调整我的断言来处理任何一种类型,但是:

I am writing unit tests for an API with many endpoints that do similar things.我正在为 API 编写单元测试,其中有许多做类似事情的端点。 I am trying to generizie my assertion code in a base class, and I just don't always know if I am dealing with an array or a List.我试图在基本 class 中泛化我的断言代码,但我并不总是知道我是在处理数组还是列表。

How can I resolve this?我该如何解决这个问题? Should I avoid using IEnumerable as return types altogether?我应该完全避免使用 IEnumerable 作为返回类型吗?

This was answered in the comments, but I hate to have this question float around without a formal answer, so allow me to recap:这在评论中得到了回答,但我不想让这个问题在没有正式答案的情况下四处流传,所以请允许我回顾一下:

public interface ITestTarget    {
    public ⚠️IEnumerable<int>⚠️ getSomeData();
}

public class TestTarget : ITestTarget     {
    public ⚠️List<int>⚠️ getSomeData() {return new List<int>() { 1 };  }
}

var testMock = new Mock<ITestTarget>();
var someResult = testMock.Object.getSomeData();

// someResult can be any type that implements IEnumerable. We cannot make
// any further assumptions. My code assumed a List.

What matters to the Mock is the type in the Interface, not the implementation.对 Mock 来说重要的是接口中的类型,而不是实现。 Thus, if no specific return type is given through a setup, you cannot make an assumption about the type that the Mock returns.因此,如果没有通过设置给出特定的返回类型,则您无法对 Mock 返回的类型做出假设。 In my case, the defaut was an array.就我而言,默认值是一个数组。 This made code invalid that attempted to access the result as a List (not in my example here).这使得试图以列表形式访问结果的代码无效(不在我的示例中)。

Casting it to an IEnumerable<T> and using ToList() , as suggested by @Guru Stron, resolves the type ambiguity and made it work for either case - a Setup that explicitely returns a List<T> or the Mock default that returns an empty <T>[] .将其转换为IEnumerable<T>并使用ToList() ,正如@Guru Stron 所建议的那样,解决了类型歧义并使其适用于任何一种情况 - 显式返回List<T>的设置或返回的 Mock 默认值空<T>[]

This really had nothing to do with Moq or unit testing but with using types and interfaces correctly.这实际上与最小起订量或单元测试无关,而是与正确使用类型和接口有关。 Now that I understand that, I can illustrate my misunderstanding differently:现在我明白了,我可以用不同的方式来说明我的误解:

    int[] a = {1,2,3};

    List<int> d = (List<int>)a;     // can't do that!
    
    List<int> c = (a as IEnumerable<int>).ToList();     // do this!

Now you may say: There are a lot of words in this post (and bandwidth needed to download them) to come to a rather trivial conclusion.现在你可能会说:这篇文章中有很多词(以及下载它们所需的带宽)来得出一个相当微不足道的结论。 I am going to downvote the question and this answer, but let me ask you this: did you know that Moq returns an array type for IEnumerables if no setup is given with another type?我将否决这个问题和这个答案,但让我问你这个问题:你知道吗,如果没有为其他类型提供设置,Moq 会为 IEnumerables 返回一个数组类型?

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

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