views:

67

answers:

2

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();
    }
}
+1  A: 

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();
Lee
It still throws the same exception.
EricSchaefer
+1  A: 

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.

Grzenio
`?? string.Empty` is not supposed to be there (I will edit it). Please read my various edits. The whole semantics of the test were wrong (not what I wanted to test). But still it is curious why rhino throws that exception. It should not care about the Name property being null.
EricSchaefer
It is very simple. You set the expectation session.InsertWithId( lockClass ); LastCall.Return( lockClass ); Rhino expects exactly this call and will compare the arguments (lock class) using the Equals method. That's why it does matter if its null or empty string. I am not sure how you would like to test it without comparing the arguments.
Grzenio
Grzenio is correct. You set up an expectation that a specific LockClass will be returned but inside your method, you create a new instance of a LockClass. Thus, the test fails. I'm not sure why you got the exception though. I tried to create a complete test using Rhino.Mocks 3.5 and I get a failing test, not an exception: http://pastebin.com/1Kb9ZxTK
Patrick Steele
LockClass implements Equals() so that two instances with the same id and the same name are considered equal.You implemented the test with MsTest. Maybe it is a problem with NUnit. I will try to create an isolated setup to reproduce the exception.
EricSchaefer