Почему RhinoMocks выдает исключение InvalidOperationException в моем тесте? - PullRequest
4 голосов
/ 02 июля 2010

Это тест, над которым я сейчас работаю:
(Отредактировано в соответствии с ответом Ли)

[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()

Есть идеи?

Edit:
Я только что понял, что он работает нормально, если первая строка метода изменилась:

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 };

Это мой ожидаемый объект. LockClass - это DTO только с двумя свойствами, инициализированными в строке выше, и обязательным Equals материалом.
Строка действия должна быть

controller.AddLockClass( lockClass.Id, null );

[SetUp] создает все макеты объектов. Я пытаюсь проверить, что если пользователь создает объект LockClass с помощью жестов GUI (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();
    }
}

Ответы [ 2 ]

3 голосов
/ 05 июля 2010

Rhino Mocks дает правильное исключение.В вашем AddLockClass есть следующая строка:

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

, которая ясно указывает, что если вы вызовете этот метод с параметром пустого имени, он все равно будет использовать пустую строку при создании экземпляра LockClass.Итак, как вы заметили в первом редактировании вашего вопроса, LockClass, который вы должны ожидать в своем тесте:

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

и не версия с нулевым значением.Дайте мне знать, если вам нужны дальнейшие разъяснения.

2 голосов
/ 02 июля 2010

Я думаю, вам нужно заключить часть теста в область действия воспроизведения:

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

mockRepository.VerifyAll();
...