Moq错误:无法将'AnObject'强制转换为'System.Delegate'

时间:2012-03-13 20:29:11

标签: c# .net nunit moq

我一直试图解决这个问题几天但现在无济于事。我正在尝试测试AnObject.AnAction的功能(抢先道歉,我必须混淆类/方法名称。)我的目标是让MyTestObj.do_work(AnObject)在调用时保持实际做任何事情。它有我希望在单元测试环境中调用的代码。

这是我的单元测试代码:

Mock< MyTestObj > myTestObj_mock = new Mock< MyTestObj > ();
myTestObj_mock.Setup( e => e.do_work( It.IsAny< AnObject > () ) );
...
AnObject tester = new AnObject();
tester.anAction( myTestObj_mock.Object );
方法AnObject.AnAction(MyTestObj mto)中的

...
mto.do_work( this );
...

正是在这个时候,我遇到了这个错误:

System.InvalidCastException : Unable to cast object of type  
'myNamespace.AnObject' to type 'System.Delegate'.     

MyTestObj.do_work是一种虚拟方法。

我完全不知道为什么会出现这个错误。当NUnit运行它时我已经完成了代码,我确信它崩溃了。它不会再进入代码了。

我真的很难过。有没有人知道发生了什么?

提前致谢!


*** 更新 * **

我试图在AnObject.AnAction中创建一个AnObject实例并传递它而不是'this':

...
AnObject test = new AnObject();
mto.do_work( test );
...

这没有任何效果。

2 个答案:

答案 0 :(得分:3)

在编写问题时,您无需设置myTestObj_mock.do_work()。

设置用于说,当方法X被称为返回值Y时。或者可选地,当调用方法X时,返回异常Z.问问自己,我真的需要做什么?

这里你没有从方法中返回任何东西:

mto.do_work( this );

另外,这里:

myTestObj_mock.Setup( e => e.do_work( It.IsAny< AnObject > () ) );

您没有为设置定义任何退货。

在这种情况下,您应该能够提供模拟myTestObj_mock而无需定义设置。只需使用安装程序删除该行并再次运行测试。

一个猜测:

如果您定义了安装程序,因为您希望测试确保AnObject.AnAction确实调用do_work方法,那么您需要做的是定义Verify方法而不是Setup,同样:

mock.Verify(foo => foo.Execute("ping"));

或在您的情况下像

myTestObj_mock.Verify(m => m.do_work(It.IsAny< AnObject > ()), Times.AtLeastOnce());

另一个猜测:

如果你定义了mock,因为你传递了一个“this”引用,并期望do_work修改一些“this”参数以便测试通过,那么你不应该在这里嘲笑。请记住,模拟不是对象的实际实例,因此修改此引用的代码永远不会被调用。

答案 1 :(得分:3)

我终于能够使用编译器并使用代码,这就是我找到的。这基本上就是贾尔斯在问题的第一部分所说的。

以下是安装程序的代码提示:

  

指定模拟类型的设置,以调用值返回方法。

而且,这是Setup

的实际代码
public ISetup<T> Setup(Expression<Action<T>> expression)

因此,安装程序实际上将代码设置为Action(基本上是委托)。当运行测试运行器时,它会到达此点并且通常期望将委托提供给Returns方法

public IReturnsResult<TMock> Returns(TResult value)

所以,这从未完成,而不是Mock在整个预期路径上运行并且协商所有代码,然后它返回错误的值。

Sooo,这基本上是Giles解释正确的地方。如果您正在测试是否正在调用do_work方法,那么您希望使用Verify(它真正使用您的虚假对象作为模拟)。但是,如果没有,那么你甚至不需要设置它,因为它什么都不做。如果是这种情况,那么这段代码可能不应该在特定的代码块中,但您最好对此进行评估。

最后,只有在您真正将对象用作存根时,才应使用Setup方法,只需使用它将逻辑注入代码即可。

希望这有意义并帮助您解决问题。

此外,Callback可能会在这里使用,具体取决于您正在做什么。但是,我不确定。他们在Moq quickstart

中有很多例子

使用版本4.0.10827更新我的尝试...并且没有问题

    [Test]
    public void teststuff()
    {
        Mock<MyTestObj> myTestObj_mock = new Mock<MyTestObj>();
        myTestObj_mock.Setup(e => e.do_work(It.IsAny<AnObject>()));
        AnObject tester = new AnObject();
        tester.anAction(myTestObj_mock.Object);
    }

...

public class MyTestObj
{
    public virtual void do_work(AnObject o)
    {

    }
}

public class AnObject
{
    public void anAction(MyTestObj obj)
    {
        obj.do_work(new AnObject());
    }
}