0

I am using moq to test C# code. The tested method has a passed in IDataReader as argument. I used Mock to mock the data reader by setup the key and value for each field (redare.Setup(x => x["fieldName"]).Returns(value)). However, we also have a method called in the tested method. The called method is testing if the field that reader is reading does exist. I found the Mocked reader doesn't have any field counted when the mocked reader casted to IDataReader by using Mocked reader.Object. Can anybody help me how to set up field counting/field name in Mock? Thanks a lot!

Update: I used this post solving my issue. Thanks for any response. How to mock IDataReader to test method which converts SqlDataReader to System.DataView

Community
  • 1
  • 1
Hao Zhou
  • 3
  • 5
  • Post your test and code under test (formatted as well) – Luke Hutton Aug 03 '16 at 21:04
  • 1
    The post you linked to demonstrates this. `dataReaderMock.Setup(x => x.FieldCount).Returns(2);`. Is that not what you're trying to do? It also suggests that if you need a more functional mock of `IDataReader` you might have to write your own implementation. I think we need more info. I can't imagine that the code you're testing would *only* require the field count, and if it did that's the easy part. It's everything else that's hard. I bet someone somewhere has written a good generic mock for this. – Scott Hannen Aug 04 '16 at 00:42

1 Answers1

0

Everything I've read so far suggests that creating a functional mock of an IDataReader is going to be at least as complex as the code you're testing, probably more so.

My recommendation would be to write an integration test, not a unit test. I typically have some helper methods in my test project that insert the records I'm expecting in my development database so that I know exactly what the test should return. After executing the test I clear out the test data.

This blog post describes it in some more detail.

For this sort of operation I trust it a lot more than a mock, because it's testing the database and my stored procedure. It's not as granular as a unit test but it serves the same purpose. If there are defects in either the stored procedure or the code that reads from it I'm going to find them easily and fix them.

I've read a number of recommendations that for some operations integration testing is more practical than unit testing (unless you can do both.) This looks like one of those cases. All the code I've seen for mocking IDataReader looks very complicated and it ends up being too different from the reality that you're testing.


In my sample code in the blog post I'm using a class to insert data and then testing to ensure that a SELECT returns the expected data.

For testing a class that reads data I'd do the opposite.

  1. Write a method in the integration test that "arranges" by inserting some test data. I usually put something in at least one of the columns like a particular string or number so that after the test I can delete exactly those records.
  2. "Act" - call the method I'm testing and have it read from the database. This typically returns some collection of objects.
  3. "Assert" that the properties of the objects returned match the values I inserted.
Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
  • Thanks, Scott! I agree the unit test becomes more complicate than the tested code itself when I try to mock DB data reader. Integration test would be a great option for that purpose. However, we have some concerns when testing code need to frequently write/delete data in DB. – Hao Zhou Aug 04 '16 at 14:20
  • It works best if you have some constant values that you use to segregate values for particular tests. That way in your test cleanup you delete it and you don't end up with any left over data. You can even generate something random for each test. But it wouldn't work in every scenario. For example, if you have triggers it would cause problems. – Scott Hannen Aug 04 '16 at 14:40