Yes, I have unit-test examples. I even wrote some for Model Explorer.
I decided not to publish them because I was worried about ME appearing too complicated. People often see test projects as evidence that a product is too complicated (sigh).
I'd actually like to do a series on unit-testing a DevForce application. Priorities.
Let me give you a few thoughts right here ... and then we can see where this leads.
Aside: We've been re-engineering some under-the-hood stuff so that DevForce is more supportive of design-first development. We've got more POCO features coming. These efforts will affect - positively - my recommendations on domain model development for the test-driven developer. I'm holding fire until we're closer to release.
One reason I'm big on the PersistenceService (PS) construct is that it makes it easy to swap a test-oriented PS for the production version. Inside the test PS, I create and configure the PS's EntityManager (EM) to facilitate testing.
Typically the test EM is defined and maintained in a disconnected state. I usually intercept all calls to SaveChanges (often by hooking the EM's "Saving" event) so that save attempts are detected and either ignored or throw an exception.
When you instantiate such a test PS, you can prime it with test entities (and entity graphs) that suit your needs. You can make these up on the spot simply by "new-ing" up entities, configuring them, and dumping them into the PS's EM. Such entities can be interrelated; DevForce will handle the navigation properties and queries gracefully. You can "accept changes" on any or all of these new entities so they appear to be unmodified entities that have been read from a data store. It's really easy to make the EM appear in exactly the state you want for your test. And you've never gone to a database nor do you have any fear of having to rollback changes that you have accidentally saved to a database.
What we're doing here is leveraging the ability of the DevForce EM to act as an in-memory datastore. In most environments, you'd have to cobble together something like this yourself. You couldn't be sure how well it simulates actual PS/EM behavior. Well, you get it all for free with DevForce because we support offline semantics out-of-the-box.
You often will want the same suite of test entities to use across a large number of unit tests. For example, it's really nice to have reference entities ("States", "Statuses", "ProductCatalog (subset)", "Colors", etc.) already in your test PS. How about some standard employees (e.g., Nancy Davolio)? You could create a test helper class to mint these and populate your test PS. This is the DataMother pattern.
It can be a super-PITA to maintain this helper class. Why not keep the test data in a database (duh)?
So l'll often populate a test database as I please and then write a little program to read the entities into an EM and export them (export the EntityCacheState) to an XML file. This is a standard DevForce technique for saving cache state for offline use. I can check this XML file into source control.
Later, when I run my unit tests, I can read and reconstitute the file as an in-memory EntityCacheState; of course I do this once per test session, not for every unit test method. Then my test PS ... which is instantiated anew for each individual unit test ... can populate itself from this EntityCacheState. Ta da! No database trip, exactly one file read, and I've got a rich DataMother under source control that everyone can share.
Aside: this approach is so convenient that I often use it for integration tests and while exploring UI changes. For example, my debug-mode solution can sport a start-up option that substitutes the test PersistenceServices for production PSs. I can save a ton of development time by shortening the Tweak-Compile-Run cycle when I have a really big app and I want to see the effect of changes to something 3 screens in that ... sadly ... doesn't have its own test harness.
You may have noticed that I am using "fakes", not "mocks" (see http://martinfowler.com/articles/mocksArentStubs.html - Fowler on this subject ). I'm preparing the state of the PS so that it supports your system under test (SUT); I'm not mocking the PS itself. You could mock your PS if you preferred. I happen to find that faking it is more useful in more of my tests because I'm usually studying something other than the behavior of the PS and having entity state around is exactly what I want. For example, if I'm confirming expectations about cross entity validations, I'm going to be messing with entity values, not watching what the PS did (or didn't) do. You'll have to figure this out for yourself.
One thing that we don't support (in any way that is obvious to me) is mocking the EntityManager itself. We don't offer an IEntityManager. I have not found this particular omission to be onerous but I'm open to discussing the subject if we can talk in terms of concrete use cases; I'm not keen on a purely philosophical / religious debate as often happens.
Hope this gives you some helpful clues. As I mentioned, I'd love to devote some energy to my personal experience with unit testing, domain model design first, and TDD ... with DevForce ... but I can't say when I'll get to it.
|