Moq It.IsSubtype 没有隐式引用转换

Red*_*ood 4 c# moq

我试图模拟一个通用方法,它有一个约束T : IFoo

但是最小起订量似乎无法理解转换并给出以下错误:

类型“Moq.It.IsSubtype<SomeNamepace.IFoo>”不能用作泛型类型或方法“IMyClass.DoSomething(Action)”中的类型参数“T”。没有从“Moq.It.IsSubtype<SomeNamepace.IFoo>”到“SomeNamepace.IFoo”的隐式引用转换。

    public interface IFoo
    {
    }

    class Foo : IFoo
    {

    }

    public interface IMyClass
    {
        public IDisposable DoSomething<T>(Action<T> asd) where T : IFoo;
    }

    public class MyTest
    {
        [Test]
        public void SomeTest()
        {
            var mock = new Mock<IMyClass>();

            mock.Setup(e => e.DoSomething(It.IsAny<Action<IFoo>>())).Returns(Mock.Of<IDisposable>());

// What I want but gives compiler error
//             mock.Setup(e => e.DoSomething(It.IsAny<Action<It.IsSubtype<IFoo>>>())).Returns(Mock.Of<IDisposable>());


// Action<IFoo> would work, but in real code its not used like that
            Action<Foo> myAction = (e) => { };
            var result = mock.Object.DoSomething(myAction);

            result.Dispose(); // Null reference exception
        }
    }
Run Code Online (Sandbox Code Playgroud)

Dav*_*idG 5

由于It.IsSubtype<IFoo>没有实现IFoo,你不能像这样使用它。由于类型限制。

但是,您可以单独使用IFoo,这应该考虑您传入的任何值,因为它们都需要实现IFoo. 换句话说,类型约束已经为您完成了确保类型正确的繁重工作。例如,给定如下设置:

public interface IFoo
{
}

public interface IMyClass
{
    string DoSomething<T>() where T : IFoo;
}
Run Code Online (Sandbox Code Playgroud)

您的测试代码将是这样的:

var mock = new Mock<IMyClass>();
mock.Setup(e => e.DoSomething<IFoo>()).Returns("cheese");

var result = mock.Object.DoSomething<IFoo>();

Assert.Equal("cheese", result); // true
Run Code Online (Sandbox Code Playgroud)

编辑:

在对问题进行补充澄清后,上面的答案仍然成立,我们可以做类似的事情:

mock
    .Setup(e => e.DoSomething<Foo>(It.IsAny<Action<Foo>>()))
    .Returns(new MyDisposableObject());
Run Code Online (Sandbox Code Playgroud)

现在我们使用它是Foo因为我们明确地知道传入的类型,所以我们不需要再担心接口了。事实上,我们甚至可以简化代码,因为我们不再需要明确泛型类型:

mock
    .Setup(e => e.DoSomething(It.IsAny<Action<Foo>>()))
    .Returns(new MyDisposableObject());
Run Code Online (Sandbox Code Playgroud)


Gur*_*ron 5

您可以创建自己的类型匹配器,它将实现IFoo以匹配通用约束:

[TypeMatcher]
public class FooTypeMatcher<T> : IFoo, ITypeMatcher
    where T : IFoo
{
    bool ITypeMatcher.Matches(Type typeArgument)
    {
        return typeof(T).IsAssignableFrom(typeArgument);
    }
}
Run Code Online (Sandbox Code Playgroud)

并设置:

mock.Setup(e => e.DoSomething(It.IsAny<Action<FooTypeMatcher<IFoo>>>())) // will match any Action accepting any IFoo implementation
    .Returns(Mock.Of<IDisposable>());
Run Code Online (Sandbox Code Playgroud)