views:

91

answers:

3

I have a class A which has the following:

public class A {
    [Import(typeof(IMyService)]
    public IMyService MyService { get; set; }

    public A() {
        CompositionInitializer.SatisfyImports(this);
    }

    public void DoWork() {
        //Blah
        MyService.DoIt();
        //Blah
    }
}

And a Test to test this (seperate Dll - obviously)

[TestMethod]
public void TestDoWork() {
    //Blah
    DoWork();
    //Assert assert
}

This fails as attempting to call 'MyService' gives me null. I've then tried:

[ClassInitialize]
public void InitialiseClass() {
    var myService = new Mock<IMyService>();
    MyService = myService.Object;
}

with 'MyService' declared as:

[Export(typeof(IMyService))]
public IMyService MyService { get; set; }

But still no joy, am I missing something - is this even possible?

I'm using SL3, MEF Preview 9 and MOQ.

Any help appreciated!

Cheers

Chris

A: 

Where you've added [Export] to your IMyService instance, have you actually added that to the composition container? If not, it won't take part in composition. To add a mocked object to the container, do the following:

 container.ComposeExportedValue<IMyService>(mock.Object);

Or just:

container.ComposeExportedValue(mock.Object); // type inference.

Doing this before you've created an instance of A will enable it to be composed inside your A instance.

Matthew Abbott
I don't need to add the concrete implementation to a container to get it to work. But I see your point. Where are you seeing the container being?
Chris
+1  A: 

Your class should look like this:

public class A 
{
    private readonly IMyService _myService;

    [ImportingConstructor]
    public A(IMyService myService)
    {
        _myService = myService;
    }

    public void DoWork() {
        //Blah
        _myService.DoIt();
        //Blah
    }
}

And your test should look like this:

[TestMethod]
public void DoWork_invokes_IMyService_DoIt() 
{
    // arrange mock and system under test
    var myService = new Mock<IMyService>();
    var a = new A(myService.Object);

    // act    
    a.DoWork();

    // assert that DoIt() was invoked
    myService.Verify(x => x.DoIt());
}

The fact that you use MEF should not be important in unit tests. MEF only comes into play when wiring many components together, which is exactly the opposite of what happens in a unit test. A unit test is by definition a test of a component in isolation.

Edit: if you prefer property injection, then your class doesn't need a constructor and the arrange part in your unit test should look like this instead:

    var myService = new Mock<IMyService>();
    var a = new A();
    a.MyService = myService.Object;
Wim Coenen
OK, but why do I need to use the constructor importer, the property is working fine in my actual implementation, presumably there is a route to be able to mock those types of imports?
Chris
@Chris: although MEF encourages property injection, I prefer construction injection because that way the compiler prevents you from creating objects with missing dependencies. It also allows you to make the dependency fields readonly, so you don't have to think about what happens if a dependency is replaced.
Wim Coenen
I've opted for this method, personally I'd still like to know if you can mock the property injection, but this helps fix the issue I had.Cheers.
Chris
@Chris: I think you missed the edit at the end of my answer.
Wim Coenen
A: 

You shouldn't be firing up MEF in your unit tests. Composition is way beyond unit test's scope, not dissimilar to an IoC container.

Insted, you should inject required dependencies manually:

[TestClass]
public class ATest {
  Mock<IMyService> myService ;
  [TestInitialize]
  public void InitialiseClass() {
    myService = new Mock<IMyService>();
  }

  [TestMethod]
  public void DoWorkShouldCallDoIt {
    A a = new A();
    a.MyService = myService.Object;
    a.DoWork();
    myService.Verify(m=>m.DoIt(), Times.Once());
  }
}
Igor Zevaka