Search code examples
c#rhino-mocks

RhinoMocks Unexpected Dispose()


Unexpected behaviour from RhinoMocks:

var mocks = new MockRepository();
var connection = mocks.Stub<OracleConnection>();
var command = mocks.Stub<OracleCommand>();

using (mocks.Record()) {
    connection.Expect(x => x.CreateCommand()).Return(command);
    command.Expect(x => x.ExecuteNonQuery());
    command.Expect(x => x.Dispose());
}

using (mocks.Playback()) {
    using(var command = connection.CreateCommand()) {
        ...
        command.ExecuteNonQuery();
    }
}

Allthough I have expected the Dispose()-Call, it is not recognized and I am getting the following message:

Rhino.Mocks.Exceptions.ExpectationViolationException: IDisposable.Dispose(); Expected #0, Actual #1.

If I rewirte the code without the using-clause everything is fine:

OracleCommand cmd = null;
try {
    command = connection.CreateCommand();
    ...
    command.ExecuteNonQuery();
}
finally {
    if (command != null)
        command.Dispose();
}

Any ideas on this issue?

Regards, MacX


Solution

  • This question and answer suggest that the problem may stem from the fact that you are stubbing out OracleCommand, rather than an IDbCommand or similar.

    The comments on the accepted answer suggest that if OracleCommand is an abstract class, you should be mocking it using GeneratePartialMock<OracleCommand>().

    I hope this helps you.

    edit

    In response to your comment, it sounds like you need the implementation-specific methods of OracleCommand, but can't mock it properly.

    Although OracleCommand is sealed, you could wrap it compositionally. It takes some legwork, but will allow you to both use OracleCommand in your code and mock it in your tests.

    public interface IOracleCommand : IDbCommand
    {
        void OracleMethod();
        string OracleProperty { get; set; }
    }
    
    public class OracleCommandWrapper : IOracleCommand
    {
        private OracleCommand _inner;
    
        public OracleCommandWrapper(OracleCommand inner)
        {
            _inner = inner;
        }
    
        public void Dispose()
        {
            _inner.Dispose();
        }
    
        public IDbDataParameter CreateParameter()
        {
            return _inner.CreateParameter();
        }
    
        // do this for all the members, including the Oracle-specific members
    
        public void OracleMethod()
        {
            _inner.OracleMethod();
        }
    
        public string OracleProperty
        {
            get { return _inner.OracleProperty; }
            set { _inner.OracleProperty = value; }
        }
    }
    

    Now you can use IOracleCommand and OracleCommandWrapper in your code, and in your tests you just mock or stub off of the IOracleCommand interface.

    Again, it takes some legwork, but gets you where you want to be.