为什么 RhinoMocks 在我的测试中抛出 InvalidOperationException?

发布于 2024-09-07 13:56:16 字数 4722 浏览 2 评论 0原文

这是我目前正在进行的测试:
(根据 Lees 的回答编辑)

[Test]
public void AddLockClassWithNullNameShouldCallInsertOnSessionWithEmptyString()
{
    LockClass lockClass = new LockClass { Id = ValidId, Name = null };

    using ( mockRepository.Record() ) {
        sessionFactory.CreateSession();
        LastCall.Return( session );

        session.InsertWithId( lockClass );
        LastCall.Return( lockClass );

        session.Commit();
        session.Dispose();
    }

    using ( mockRepository.Playback() ) {
        controller = new LockClassPanelController( sessionFactory );
        controller.AddLockClass( lockClass.Id, string.Empty );
    }

    mockRepository.VerifyAll();
}

运行测试结果为:

Test 'Test.Unit.Controllers.LockClassPanelControllerTests.AddLockWithNullNameClassShouldCallInsertOnSessionWithEmptyString' failed:
 System.InvalidOperationException : The operation is invalid because of the current object state. (translated from german, dunno if thats the original english wording)
 at System.Reflection.RuntimeMethodInfo.GetGenericMethodDefinition()
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.MethodsEquals(MethodInfo method, ProxyMethodExpectationTriplet triplet)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.GetAllExpectationsForProxyAndMethod(Object proxy, MethodInfo method)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.CalcExpectedAndActual.Calculate(Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.CalcExpectedAndActual..ctor(UnorderedMethodRecorder parent, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.UnexpectedMethodCall(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.DoGetRecordedExpectation(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.MethodRecorders.MethodRecorderBase.GetRecordedExpectation(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.Impl.ReplayMockState.DoMethodCall(IInvocation invocation, MethodInfo method, Object[] args)
 at Rhino.Mocks.Impl.ReplayMockState.MethodCall(IInvocation invocation, MethodInfo method, Object[] args)
 at Rhino.Mocks.MockRepository.MethodCall(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.Impl.RhinoInterceptor.Intercept(IInvocation invocation)
 at Castle.DynamicProxy.AbstractInvocation.Proceed()
 at ISessionProxy2762dfaac4274133bc97e10d4e5c35d0.InsertWithId[TEntity](TEntity entity)
 Controllers\LockClassPanelController.cs(20,0): at Artea.Service.Controllers.LockClassPanelController.AddLockClass(Int32 id, String name)
 Unit\Controllers\LockClassPanelControllerTests.cs(80,0): at Test.Unit.Controllers.LockClassPanelControllerTests.AddLockWithNullNameClassShouldCallInsertOnSessionWithEmptyString()

有什么想法吗?

编辑:
我刚刚发现,如果更改方法的第一行,它就可以正常工作:(

LockClass lockClass = new LockClass { Id = ValidId, Name = string.Empty };

string.Empty 而不是 null) 但是测试应该检查如果 Name 属性为 null 会发生什么,因此将 Name 设为除 null 以外的任何其他值都不会很有帮助。

编辑:
该代码实际上没有测试我想测试的内容。该方法的第一行应该是

LockClass lockClass = new LockClass { Id = ValidId, Name = string.Empty };

Thats myected object。 LockClass 是一个 DTO,仅包含上面一行中初始化的两个属性以及必需的 Equals 内容。
行为行应该是

controller.AddLockClass( lockClass.Id, null );

[SetUp] 创建所有模拟对象。我想要测试的是,如果用户通过 GUI 手势创建一个 LockClass 对象(GUI 在控制器上调用 AddLockClass),其中名称为 null,则控制器会创建一个名称为空的对象。还有其他方法可以做到这一点,但现在必须采用这种方式。更改后的代码确实有效(例如,Rhino 不会呕吐)。我仍然保留这个问题,因为很好奇为什么 Rhino 不喜欢原始代码。

要使其完整:

private const int ValidId = 4711;
private const int InvalidId = 0;
private MockRepository mockRepository;
private ISessionFactory sessionFactory;
private ISession session;
private LockClassPanelController controller;

[SetUp]
public void Setup()
{
    mockRepository = new MockRepository();
    sessionFactory = mockRepository.StrictMock<ISessionFactory>();
    session = mockRepository.StrictMock<ISession>();
}

编辑:

public void AddLockClass( int id, string name )
{
    if ( id != 0 ) {
        using ( var session = sessionFactory.CreateSession() ) {
            session.InsertWithId( new LockClass { Id = id, Name = name } );
            session.Commit();
        }
        LoadLockClasses();
        view.Initialize();
    }
}

This is a test I am currently working on:
(Edited according to Lees answer)

[Test]
public void AddLockClassWithNullNameShouldCallInsertOnSessionWithEmptyString()
{
    LockClass lockClass = new LockClass { Id = ValidId, Name = null };

    using ( mockRepository.Record() ) {
        sessionFactory.CreateSession();
        LastCall.Return( session );

        session.InsertWithId( lockClass );
        LastCall.Return( lockClass );

        session.Commit();
        session.Dispose();
    }

    using ( mockRepository.Playback() ) {
        controller = new LockClassPanelController( sessionFactory );
        controller.AddLockClass( lockClass.Id, string.Empty );
    }

    mockRepository.VerifyAll();
}

Running the test results in:

Test 'Test.Unit.Controllers.LockClassPanelControllerTests.AddLockWithNullNameClassShouldCallInsertOnSessionWithEmptyString' failed:
 System.InvalidOperationException : The operation is invalid because of the current object state. (translated from german, dunno if thats the original english wording)
 at System.Reflection.RuntimeMethodInfo.GetGenericMethodDefinition()
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.MethodsEquals(MethodInfo method, ProxyMethodExpectationTriplet triplet)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.GetAllExpectationsForProxyAndMethod(Object proxy, MethodInfo method)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.CalcExpectedAndActual.Calculate(Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.CalcExpectedAndActual..ctor(UnorderedMethodRecorder parent, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.UnexpectedMethodCall(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.DoGetRecordedExpectation(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.MethodRecorders.MethodRecorderBase.GetRecordedExpectation(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.Impl.ReplayMockState.DoMethodCall(IInvocation invocation, MethodInfo method, Object[] args)
 at Rhino.Mocks.Impl.ReplayMockState.MethodCall(IInvocation invocation, MethodInfo method, Object[] args)
 at Rhino.Mocks.MockRepository.MethodCall(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
 at Rhino.Mocks.Impl.RhinoInterceptor.Intercept(IInvocation invocation)
 at Castle.DynamicProxy.AbstractInvocation.Proceed()
 at ISessionProxy2762dfaac4274133bc97e10d4e5c35d0.InsertWithId[TEntity](TEntity entity)
 Controllers\LockClassPanelController.cs(20,0): at Artea.Service.Controllers.LockClassPanelController.AddLockClass(Int32 id, String name)
 Unit\Controllers\LockClassPanelControllerTests.cs(80,0): at Test.Unit.Controllers.LockClassPanelControllerTests.AddLockWithNullNameClassShouldCallInsertOnSessionWithEmptyString()

Any ideas?

Edit:
I just figured out that it works fine if the first line of the method is changed:

LockClass lockClass = new LockClass { Id = ValidId, Name = string.Empty };

(string.Empty instead of null)
But the test is supposed to check what happens if the Name property is null, so having Name being anything else but null would not be very helpful.

Edit:
The code is actually not testing what i I wanted to test. The first line of the method should be

LockClass lockClass = new LockClass { Id = ValidId, Name = string.Empty };

Thats my expected object. LockClass is a DTO with only the two properties initialized in above line and the obligatory Equals stuff.
The act line should be

controller.AddLockClass( lockClass.Id, null );

[SetUp] creates all the mocked objects. What I am trying to test is that if the user creates a LockClass object though GUI gestures (the GUI calls AddLockClass on the controller) where the name is null the controller creates an object with an empty name. There are other ways to do that, but right now it has to be this way. The changed code does work (e.g. Rhino does not throw up). I am still keeping the question because it is curious why Rhino does not like the original code.

To make it complete:

private const int ValidId = 4711;
private const int InvalidId = 0;
private MockRepository mockRepository;
private ISessionFactory sessionFactory;
private ISession session;
private LockClassPanelController controller;

[SetUp]
public void Setup()
{
    mockRepository = new MockRepository();
    sessionFactory = mockRepository.StrictMock<ISessionFactory>();
    session = mockRepository.StrictMock<ISession>();
}

Edit:

public void AddLockClass( int id, string name )
{
    if ( id != 0 ) {
        using ( var session = sessionFactory.CreateSession() ) {
            session.InsertWithId( new LockClass { Id = id, Name = name } );
            session.Commit();
        }
        LoadLockClasses();
        view.Initialize();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独﹏钓一江月 2024-09-14 13:56:17

我认为您需要将测试的“act”部分包含在播放范围内:

using(mockRepository.Playback())
{
    controller = new LockClassPanelController( sessionFactory ); 
    controller.AddLockClass( lockClass.Id, string.Empty );
}

mockRepository.VerifyAll();

I think you need to enclose the 'act' part of the test inside a playback scope:

using(mockRepository.Playback())
{
    controller = new LockClassPanelController( sessionFactory ); 
    controller.AddLockClass( lockClass.Id, string.Empty );
}

mockRepository.VerifyAll();
天生の放荡 2024-09-14 13:56:16

Rhino Mocks 为您提供正确的异常。在 AddLockClass 中,您有以下行:

session.InsertWithId( new LockClass { Id = id, Name = ( name ?? string.Empty ) } );

它清楚地表明,如果您使用 null 名称参数调用此方法,则在创建 LockClass 实例时,它仍将使用空字符串。因此,正如您在问题的第一次编辑中注意到的那样,您在测试中应该期望的 LockClass 是:

LockClass lockClass = new LockClass { Id = ValidId, Name = string.Empty };

而不是带有 null 的版本。如果您需要进一步说明,请告诉我。

Rhino Mocks gives you correct exception. In your AddLockClass you have the following line:

session.InsertWithId( new LockClass { Id = id, Name = ( name ?? string.Empty ) } );

which clearly indicates that if you call this method with null name parameter, it will still use empty string when creating the LockClass instance. So as you noticed in the first edit of your question, the LockClass that you should expect in your test is:

LockClass lockClass = new LockClass { Id = ValidId, Name = string.Empty };

and not the version with null. Let me know if you need further clarification.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文