Moq It.IsSubtype 没有隐式引用转换
Moq It.IsSubtype has no implicit reference conversion
我正在尝试模拟一个通用方法,它具有 T : IFoo
的约束
但是 moq 似乎无法理解转换并给出以下错误:
The type 'Moq.It.IsSubtype<SomeNamepace.IFoo>'
cannot be used as type parameter 'T' in the generic type or method
'IMyClass.DoSomething(Action)'. There is no implicit reference
conversion from
'Moq.It.IsSubtype<SomeNamepace.IFoo>' to
'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
}
}
因为It.IsSubtype<IFoo>
没有实现IFoo
,你不能这样使用它。由于类型限制。
但是,您可以单独使用 IFoo
,这应该考虑您传入的任何值,因为它们都需要实现 IFoo
。换句话说,类型约束已经为您完成了确保类型正确的繁重工作。例如,给定这样的设置:
public interface IFoo
{
}
public interface IMyClass
{
string DoSomething<T>() where T : IFoo;
}
你的测试代码就是这样:
var mock = new Mock<IMyClass>();
mock.Setup(e => e.DoSomething<IFoo>()).Returns("cheese");
var result = mock.Object.DoSomething<IFoo>();
Assert.Equal("cheese", result); // true
编辑:
经过对问题的补充说明,上面的答案仍然成立,我们可以做类似的事情:
mock
.Setup(e => e.DoSomething<Foo>(It.IsAny<Action<Foo>>()))
.Returns(new MyDisposableObject());
现在我们正在使用 Foo
,因为我们明确知道传入的类型,因此我们无需再担心接口。事实上,我们甚至可以简化代码,因为我们不再需要明确泛型类型:
mock
.Setup(e => e.DoSomething(It.IsAny<Action<Foo>>()))
.Returns(new MyDisposableObject());
您可以创建自己的类型匹配器,它将实现 IFoo
以匹配通用约束:
[TypeMatcher]
public class FooTypeMatcher<T> : IFoo, ITypeMatcher
where T : IFoo
{
bool ITypeMatcher.Matches(Type typeArgument)
{
return typeof(T).IsAssignableFrom(typeArgument);
}
}
和设置:
mock.Setup(e => e.DoSomething(It.IsAny<Action<FooTypeMatcher<IFoo>>>())) // will match any Action accepting any IFoo implementation
.Returns(Mock.Of<IDisposable>());
我正在尝试模拟一个通用方法,它具有 T : IFoo
但是 moq 似乎无法理解转换并给出以下错误:
The type 'Moq.It.IsSubtype<SomeNamepace.IFoo>' cannot be used as type parameter 'T' in the generic type or method 'IMyClass.DoSomething(Action)'. There is no implicit reference conversion from 'Moq.It.IsSubtype<SomeNamepace.IFoo>' to '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
}
}
因为It.IsSubtype<IFoo>
没有实现IFoo
,你不能这样使用它。由于类型限制。
但是,您可以单独使用 IFoo
,这应该考虑您传入的任何值,因为它们都需要实现 IFoo
。换句话说,类型约束已经为您完成了确保类型正确的繁重工作。例如,给定这样的设置:
public interface IFoo
{
}
public interface IMyClass
{
string DoSomething<T>() where T : IFoo;
}
你的测试代码就是这样:
var mock = new Mock<IMyClass>();
mock.Setup(e => e.DoSomething<IFoo>()).Returns("cheese");
var result = mock.Object.DoSomething<IFoo>();
Assert.Equal("cheese", result); // true
编辑:
经过对问题的补充说明,上面的答案仍然成立,我们可以做类似的事情:
mock
.Setup(e => e.DoSomething<Foo>(It.IsAny<Action<Foo>>()))
.Returns(new MyDisposableObject());
现在我们正在使用 Foo
,因为我们明确知道传入的类型,因此我们无需再担心接口。事实上,我们甚至可以简化代码,因为我们不再需要明确泛型类型:
mock
.Setup(e => e.DoSomething(It.IsAny<Action<Foo>>()))
.Returns(new MyDisposableObject());
您可以创建自己的类型匹配器,它将实现 IFoo
以匹配通用约束:
[TypeMatcher]
public class FooTypeMatcher<T> : IFoo, ITypeMatcher
where T : IFoo
{
bool ITypeMatcher.Matches(Type typeArgument)
{
return typeof(T).IsAssignableFrom(typeArgument);
}
}
和设置:
mock.Setup(e => e.DoSomething(It.IsAny<Action<FooTypeMatcher<IFoo>>>())) // will match any Action accepting any IFoo implementation
.Returns(Mock.Of<IDisposable>());