views:

2485

answers:

4

Just starting out with Rhino Mocks and im having a very simple problem, how do I mock a class with a void which sets a property?

class SomeClass : ISomeClass
{
    private bool _someArg;

    public bool SomeProp { get; set; }

    public SomeClass(bool someArg)
    {
        _someArg = someArg; 
    }

    public void SomeMethod()
    {
        //do some file,wcf, db operation here with _someArg
        SomeProp = true/false;
    }
}

Obviously this is a very contrived example, Thanks.

+2  A: 

Depends on how much fidelity you'd like in your mock object. The easy way to do it is to not worry about it and write out some dumb expect statements.

[Test]
public void SomeTest()
{
   MockRepository mocks = new MockRepository();
   ISomeClass mockSomeClass = mocks.StrictMock<ISomeClass>();
   using(mocks.Record())
   {
      using(mocks.Ordered())
      {
         Expect.Call(MockSomeClass.SomeProp).Return(false);
         Expect.Call(delegate{MockSomeClass.SomeMethod();});
         Expect.Call(MockSomeClass.SomeProp).Return(true);
      }
   }
}

If you want something that acts more like the real object without a canned set of ordered responses you'll have to set up delegates with the do method on the expect.

delegate bool propDelegate();
delegate void methodDelegate();
private bool m_MockPropValue = false;

[Test]
public void SomeTest()
{
   MockRepository mocks = new MockRepository();
   ISomeClass mockSomeClass = mocks.StrictMock<ISomeClass>();
   using(mocks.Record())
   {
      SetupResult.For(MockSomeClass.SomeProp).Do(new propDelegate(delegate
      {
         return this.m_MockPropValue;
      }));
      Expect.Call(delegate{MockSomeClass.SomeMethod();}).Do(new methodDelegate(delegate
      {
         this.m_MockPropValue = true;
      }));
   }
}
Scott Pedersen
And how do I assert that SomeMethod was called?
Lee Treveil
By using Expect.Call(s => s.SomeMethod())
Slace
Expanding on Slace's comment, Following the using(mocks.Record()) block you would have a using(mocks.Playback()) block. When you leave the playback block, any expectation you set up in the record block that has not been fulfilled will result in a failed test.
Scott Pedersen
A: 

When your preparing something with either SetupResult.For or Expect.Call you need to ensure that they are virtual, otherwise RhinoMocks will be unable to make its own implementation.

Otherwise it's just a matter of setting the results and doing expected calls as Scott Pedersen has shown

Slace
A: 

It's not totally clear from the question what the object you're trying to test is - if you simply want to check that SomeClass.SomeMethod() sets a property then you don't need mocking since you can just do a simple state-based test:

[TestMethod]
public void SomeMethodTest()
{
    SomeClass s = new SomeClass();
    s.SomeMethod();

    Assert.AreEqual(expectedValue, s.SomeProp);
}

Alternatively, if SomeClass is a dependency for some other class, and you want to test the interaction between that class and SomeClass, then you set up the expectation on the method call during the 'Record' section of the test using RhinoMock, like this:

[TestMethod]
    public void CheckInteractionWithSomeClass()
    {
        MockRepository mocks = new MockRepository();
        ISomeClass someClass = mocks.StrictMock<ISomeClass>();

        using (mocks.Record())
        {
            //record expection that someClass.SomeMethod will be called...
            someClass.SomeMethod();
        }

        using (mocks.Playback())
        {
            //setup class under test - ISomeClass is injected through the constructor here...
            ClassUnderTest o = new ClassUnderTest(someClass);

            o.MethodOnClassUnderTestThatShouldCallSomeClass.SomeMethod();

            //any other assertions...
        }
    }
Lee
+5  A: 

In your example you won't need RhinoMocks because you're apparently testing the functionality of the class under test. Simple unit testing will do instead:

[Test]
public void SomeTest()
{
    var sc = new SomeClass();
        // Instantiate SomeClass as sc object
    sc.SomeMethod();
        // Call SomeMethod in the sc object.

    Assert.That(sc.SomeProp, Is.True );
        // Assert that the property is true... 
        // or change to Is.False if that's what you're after...
}

It's much more interesting to test mocks when you have a class that has dependencies on other classes. In your example you mention:

//do some file, wcf, db operation here with _someArg

I.e. you expect some other class to set SomeClass's property, which makes more sense to mocktest. Example:

public class MyClass {

    ISomeClass _sc;

    public MyClass(ISomeClass sc) {
        _sc = sc;
    }

    public MyMethod() {
        sc.SomeProp = true;
    }

}

The required test would go something like this:

[Test]
public void MyMethod_ShouldSetSomeClassPropToTrue()
{
    MockRepository mocks = new MockRepository();
    ISomeClass someClass = mocks.StrictMock<ISomeClass>();

    MyClass classUnderTest = new MyClass(someClass);

    someClass.SomeProp = true;
    LastCall.IgnoreArguments();
        // Expect the property be set with true.

    mocks.ReplayAll();

    classUndertest.MyMethod();
        // Run the method under test.

    mocks.VerifyAll();
}
Spoike
In your last example, the Lastcall.IgnoreArguments(); would be a false pass because you could also have the test pass by passing someClass.SomeProp = false;
mendicant