11

I'm trying to mock a SqlDataReader

 SqlDataReader reader = mocks.CreateMock<SqlDataReader>();
 Expect.Call(reader.Read()).Return(true).Repeat.Times(1);
 Expect.Call(reader.Read()).Return(false);
 Expect.Call(reader.HasRows).Return(true);
 Expect.Call(reader.Dispose);
 Expect.Call(reader["City"]).Return("Boise");
 Expect.Call(reader["State"]).Return("State");
 Expect.Call(reader["LAT"]).Return(100);
 Expect.Call(reader["LON"]).Return(-100);
 mocks.ReplayAll();

but I keep getting a Rhino.Mocks.Exceptions.ExpectationViolationException: IDisposable.Dispose(); Expected #0, Actual #1 error in my method

        using (reader)
        {
            if (reader.HasRows)
            {
                while (reader.Read())
                {
                    CityState myCity = new CityState
                       {
                           City = reader["City"].ToString(),
                           State = reader["State"].ToString(),
                           Lat = Convert.ToInt32(reader["LAT"]),
                           Lon = Convert.ToInt32(reader["LON"])
                       };
                    myCities.Add(myCity);
                }                    
            }               
        }

am I missing something?

Bob The Janitor
  • 20,292
  • 10
  • 49
  • 72

1 Answers1

10

I will suggest you a rewrite of the test using AAA syntax and using an interface (IDataReader) instead of concrete type (SqlDataReader):

// Arrange
IDataReader reader = MockRepository.GenerateStub<IDataReader>();
reader.Stub(x => x.Read()).Repeat.Once().Return(true);
reader.Stub(x => x.Read()).Return(false);
reader.Stub(x => x["City"]).Return("Boise");
reader.Stub(x => x["State"]).Return("State");
reader.Stub(x => x["LAT"]).Return(100);
reader.Stub(x => x["LON"]).Return(-100);

// Act
var myCities = new List<CityState>();
using (reader)
{
    while (reader.Read())
    {
        CityState myCity = new CityState
        {
            City = reader["City"].ToString(),
            State = reader["State"].ToString(),
            Lat = Convert.ToInt32(reader["LAT"]),
            Lon = Convert.ToInt32(reader["LON"])
        };
        myCities.Add(myCity);
    }
}

// Assert
Assert.AreEqual(1, myCities.Count);
Assert.AreEqual("Boise", myCities[0].City);
...
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • I assume that since this answer was accepted, it must have solved the problem. But the question remains: Why did it work? I have the same issue with IDisposable (I'm trying to mock System.IO.Stream), and I can't figure out why my stubbed Dispose() isn't getting called. – Bruce Johnston Sep 26 '10 at 02:33
  • 2
    It works because we replaced `SqlDataReader` with `IDataReader` and mocked this `IDataReader`. In your case it seems that you are working with an abstract class instead of an interface. In this case you need to create the mocked object with `MockRepository.GeneratePartialMock()` and defined expectations on it using `streamMock.Expect(x => x.Dispose()).Throw(new Exception("foo"));`. – Darin Dimitrov Sep 26 '10 at 09:17
  • Does this example run on your machine once you add an implementation for CityState? If not, could you provide the full code so it does run? It does not for me with Moq 4.0.10827 even after using var reader = new Mock() and reader.Setup(...). – Lernkurve Jan 12 '11 at 13:20