views:

302

answers:

2

A few weeks ago I jumped on the MEF (ComponentModel) bandwagon, and am now using it for a lot of my plugins and also shared libraries. Overall, it's been great aside from the frequent mistakes on my part, which result in frustrating debugging sessions.

Anyhow, my app has been running great, but my MEF-related code changes have caused my automated builds to fail. Most of my unit tests were failing simply because the modules I was testing were dependent upon other modules that needed to be loaded by MEF. I worked around these situations by bypassing MEF and directly instantiating those objects.

In other words, via MEF I would have something like

[Import]
public ICandyInterface ci { get; set; }

and

[Export(typeof(ICandyInterface))]
public class MyCandy : ICandyInterface
{
    [ImportingConstructor]
    public MyCandy( [Import("name_param")] string name) {}
    ...
}

But in my unit tests, I would just use

CandyInterface MyCandy = new CandyInterface( "Godiva");

In addition, the CandyInterface requires a connection to a database, which I have worked around by just adding a test database to my unit test folder, and I have NUnit use that for all of the tests.

Ok, so here are my questions regarding this situation:

  1. Is this a Bad Way to do things?
  2. Would you recommend composing parts in [SetUp]
  3. I haven't yet learned how to use mocks in unit testing -- is this a good example of a case where I might want to mock the underlying database connection (somehow) to just return dummy data and not really require a database?
  4. If you've encountered something like this before, can you offer your experience and the way you solved your problem? (or should this go into the community wiki?)
+4  A: 

It sounds like you are on the right track. A unit test should test a unit, and that's what you do when you directly create instances. If you let MEF compose instances for you, they would tend towards integration tests. Not that there's anything wrong with integration tests, but unit tests tend to be more maintainable because you test each unit in isolation.

You don't need a container to wire up instances in unit tests.

I generally recommend against composing Fixtures in SetUp, as it leads to the General Fixture anti-pattern.

It is best practice to replace dependencies with Test Doubles. Dynamic mocks is one of the more versatile ways of doing this, so definitely something you should learn.

Mark Seemann
That's some great advice, Mark. Thank you very much for your input!
Dave
I read the articles that you had posted, and they were very informative. So it sounds like my current test that creates the SQLite-dependent object should instead have another ICandyInterface test stub (or mock object? I don't yet see the difference) that just returns whatever data I would expect to get from the DB, without actually using a DB.
Dave
That sounds correct, yet :)
Mark Seemann
brilliant, that totally works. thank you!
Dave