How do you unit test a class that's meant to talk to data?
I have a few repository classes that are meant to talk to different kinds of data, deriving from an IRepository
interface.
In implementations, the code talks to a data source, be this a directory of XML files o开发者_JS百科r a database or even just a cache. Is it possible to reliably unit test any of these implementations? I don't see a mock implementation working, because then I'm only testing the mock code and not the actual code.
No, you'd use a mock when you were writing a class which uses an IRepository
. For the implementations of IRepository
, you'd need to test against the appropriate data source. For databases, that's a bit of a pain - for a file system, slightly less so.
Where possible, if you can express your implementation in terms of streams or readers, you will make your life easier: tests for those parts of the implementation can go against in-memory data sources, or streams from resources in the test assembly. Of course you'll probably need some tests which go to a real database or the file system, but hopefully fewer.
Whether you'd call such tests "unit" tests or not is a matter of how you define unit tests; personally I don't care too much about the names involved, but I do care about having tests. For databases in particular, these can be somewhat painful (especially if you want to be able to run tests in parallel) - but they can also be incredibly valuable, in my experience.
I think if you are testing code that actually persists or queries data, you probably actually want to hit a database.
These are integration tests rather than unit tests.
You could set up a test database, in which you know the state of the data, and run the tests against this. You probably also want to tell the tests that they are different from your unit tests and do not need to be run on every check in (in nUnit you can decorate your test class with an attribute telling it not to run)
Broadly speaking, you won't unit test any code whose only purpose is to talk to a data source. You may still want to automatically test the repository, but such a test will be an integration test by definition. You probably don't want to run those tests as part of your "first pass" builds as e.g. setting up the database and cleaning up after yourself can take a non-insignificant amount of time.
If your repository has other responsibilities (e.g. implementing the Unit of Work pattern), then you may want to unit test those separately.
At some point in the implementation of the IRepository you will use a third party API that will actually read/write to/from database/file/xml. What you want to do is to mock those APIs to make sure your code calls the right API in the right order.
So if you are reading from the database you can mock SqlConnection and SqlCommand and make sure you call the right methods on those classes. If you are writing to a stream, you can mock the stream and make sure you Flush it and Dispose it (for example).
精彩评论