views:

452

answers:

3

I am trying to test the logic from some existing classes. It is not possible to re-factor the classes at present as they are very complex and in production.

What I want to do is create a mock object and test a method that internally calls another method that is very hard to mock.

So I want to just set a behaviour for the secondary method call.

But when I setup the behaviour for the method, the code of the method is invoked and fails.

Am I missing something or is this just not possible to test without re-factoring the class?

I have tried all the different mock types (Strick,Stub,Dynamic,Partial ect.) but they all end up calling the method when I try to set up the behaviour.

using System;
using MbUnit.Framework;
using Rhino.Mocks;

namespace MMBusinessObjects.Tests
{
    [TestFixture]
    public class PartialMockExampleFixture
    {
        [Test]
        public void Simple_Partial_Mock_Test()
        {
            const string param = "anything";

            //setup mocks
            MockRepository mocks = new MockRepository();


            var mockTestClass = mocks.StrictMock<TestClass>();

            //record beahviour *** actualy call into the real method stub ***
            Expect.Call(mockTestClass.MethodToMock(param)).Return(true);

            //never get to here
            mocks.ReplayAll();

            //this is what i want to test
            Assert.IsTrue(mockTestClass.MethodIWantToTest(param));


        }

        public class TestClass
        {
            public bool MethodToMock(string param)
            {
                //some logic that is very hard to mock
                throw new NotImplementedException();
            }

            public bool MethodIWantToTest(string param)
            {
                //this method calls the 
                if( MethodToMock(param) )
                {
                    //some logic i want to test
                }

                return true;
            }
        }
    }
}
+1  A: 

I recommend not mocking methods in the class under test, but your situation may be unique in that you can't refactor the class to make it easier to test at present. You might try explicitly making a delegate to prevent the method from being invoked when setting up the call.

 Expect.Call( delegate { mockTestClass.MethodToMock(param) } ).Return(true);

Or, switch to using the AAA syntax, omitting the deprecated constructs.

    [Test]
    public void Simple_Partial_Mock_Test()
    {
        const string param = "anything";

        var mockTestClass = MockRepository.GenerateMock<TestClass>();

        mockTestClass.Expect( m => m.MethodToMock(param) ).Return( true );

        //this is what i want to test
        Assert.IsTrue(mockTestClass.MethodIWantToTest(param));

        mockTestClass.VerifyAllExpectations();
    }
tvanfosson
The AAA syntax should work fine. +1 for using it.
iCe
Thanks for your help, I tried what you said but in this simple example it still throws the exception on the line mockTestClass.Expect( m => m.MethodToMock(param) ).Return( true ); calls the classes MethodToMock which will throw a NotImplementedException.
dotnet crazy kid
+2  A: 

MethodToMock is not virtual and therefore can't be mocked. What you want to do is possible with a partial mock (I've done it in cases similar to yours), but the method you want to mock out must be either part of an interface implementation or be marked virtual. Otherwise, you can't mock it with Rhino.Mocks.

Patrick Steele
Totally missed that -- you're absolutely correct.
tvanfosson
A: 

I have tried to use a partial mock but the following does not work anyone clarify why

using System;
using MbUnit.Framework;
using Rhino.Mocks;

namespace MMBusinessObjects.Tests
{
    [TestFixture]
    public class PartialMockExampleFixture
    {

        [Test]
        public void Simple_Partial_Mock_Test()
        {
            const string param = "anything";

            var mockTestClass = MockRepository.GeneratePartialMock<TestClass>();

            mockTestClass.Expect(m => m.MethodToMock(param)).Return(true); 

            //this is what i want to test 
            Assert.IsTrue(mockTestClass.MethodIWantToTest(param));

            mockTestClass.VerifyAllExpectations();
        }

        public interface ITestClass
        {
            bool MethodToMock(string param);
            bool MethodIWantToTest(string param);
        }

        public class TestClass :  ITestClass
        {
            public bool MethodToMock(string param)
            {
                //some logic that is very hard to mock
                throw new NotImplementedException();
            }

            public bool MethodIWantToTest(string param)
            {
                //this method calls the 
                if (MethodToMock(param))
                {
                    //some logic i want to test
                }

                return true;
            }
        }
    }
}

it works if you declare the method virtual tho

using System;
using MbUnit.Framework;
using Rhino.Mocks;

namespace MMBusinessObjects.Tests
{
    [TestFixture]
    public class PartialMockExampleFixture
    {

        [Test]
        public void Simple_Partial_Mock_Test()
        {
            const string param = "anything";

            var mockTestClass = MockRepository.GeneratePartialMock<TestClass>();

            //mockTestClass.Expect(m => m.MethodToMock(param)).Return(true); 

            //this is what i want to test 
            Assert.IsTrue(mockTestClass.MethodIWantToTest(param));

            mockTestClass.VerifyAllExpectations();
        }


        public class TestClass 
        {
            public virtual bool MethodToMock(string param)
            {
                //some logic that is very hard to mock
                throw new NotImplementedException();
            }

            public bool MethodIWantToTest(string param)
            {
                //this method calls the 
                if (MethodToMock(param))
                {
                    //some logic i want to test
                }

                return true;
            }
        }
    }
}
dotnet crazy kid
Instead of using "var", make 'mockTestClass' an ITestClass type. By using var, 'mockTestClass' represents an instance of TestClass, not an ITestClass. So you can't mock the (non-virtual) method.
Patrick Steele
ok tried that Patrick, but it still calles in the logic and throws the NotImplementedException
dotnet crazy kid
Sorry. My bad. You're still mocking an actual class, so the method must be virtual for Rhino.Mocks to intercept it and return a specific response. If you were creating just a stub for ITestClass, you'd be okay. But since you're doing a partial mock, you still need the methods to be virtual. Sorry for the confusion.
Patrick Steele