Ok, think I have something half baked now that the others won't have issues with. Any takers on a peer review on this? The idea is that this 'helper' method could be extracted out into a utility class for the test project.
I changed my calls from MockAll to Mock, because MockAll wasn't needed. Notice I added a second test that returns multiple records just to show the reusability of the call, but of interest I also added a reflective ExpectAlways to 'setConnection' - this is because for demoing purpose I used a different 'style' of doing the database connection - I used connection string, instead of using constructor (at bottom). It seems like this could be cleaned up some more and maybe there's a way to get rid of the reflective mocks and use natural mocks, but I'm not smart enough to figure out how.
[TestMethod(), VerifyMocks()]
public void GetUserTest()
{
SqlDataReader dr = SetUpMocksForDatabaseCallAndReturnReader();
using (RecordExpectations recorder = new RecordExpectations())
{
recorder.ExpectAndReturn(dr.Read(), true);
recorder.ExpectAndReturn(dr.GetString(0), "BOB").CheckArguments(0);
}
TestDBMock_Accessor accessor = new TestDBMock_Accessor();
Assert.AreEqual<string>("BOB", accessor.GetUser());
}
static bool _isCalled = false;
private static SqlDataReader SetUpMocksForDatabaseCallAndReturnReader()
{
SqlDataReader dr = RecorderManager.CreateMockedObject<SqlDataReader>();
Mock<SqlConnection> mockedConn =
MockManager.Mock<SqlConnection>(Constructor.Mocked);
mockedConn.ExpectAlways("Open", null);
mockedConn.ExpectAlways("Close", null);
mockedConn.ExpectAlways("Dispose", null);
mockedConn.ExpectAlways("set_ConnectionString", null);
Mock<SqlCommand> mockedCmd = MockManager.Mock<SqlCommand>(Constructor.Mocked);
mockedCmd.AlwaysReturn("ExecuteReader", dr, null);
return dr;
}
[TestMethod(), VerifyMocks()]
public void GetUsersTest()
{
SqlDataReader dr = SetUpMocksForDatabaseCallAndReturnReader();
using (RecordExpectations recorder = new RecordExpectations())
{
recorder.ExpectAndReturn(dr.Read(), true);
recorder.ExpectAndReturn(dr.GetString(0), "BOB").CheckArguments(0);
recorder.ExpectAndReturn(dr.Read(), true);
recorder.ExpectAndReturn(dr.GetString(0), "TOM").CheckArguments(0);
recorder.ExpectAndReturn(dr.Read(), true);
recorder.ExpectAndReturn(dr.GetString(0), "JOE").CheckArguments(0);
}
TestDBMock_Accessor accessor = new TestDBMock_Accessor();
List<string> users = accessor.GetUsers();
Assert.AreEqual<int>(3, users.Count);
//No value in these checks, just demoing...
Assert.AreEqual<string>("BOB", users[0]);
Assert.AreEqual<string>("TOM", users[1]);
Assert.AreEqual<string>("JOE", users[2]);
}
I would like to understand MockManager better though - is it static? I mean, since I asked the manager to mock SqlConnection, do I really need to do it on the next test too, or is it already mocked from the previous test? If it is static...how do I 'unmock' it?
Different 'style' of dealing from original with ADO.NET calls, the utility test helper method above handles without problem:
public List<string> GetUsers()
{
List<string> users = new List<string>();
using (SqlConnection conn = new SqlConnection())
{
//Set connection here instead of constructor
conn.ConnectionString = "NotReal";
//Don't use 'using statement'
SqlCommand cmd = new SqlCommand("TEST");
//Set connection after creation.
cmd.Connection = conn;
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
users.Add(dr.GetString(0));
}
}
cmd.Dispose();
}
return users;
}