tags:

views:

588

answers:

2

I am attempting to use the shared part creation policy for a MEF export. It does not, however, seem to work the way I was thinking. I do the composition twice in my application and each time get a fresh copy of the object. I've proved this by adding an instance counter to the object instanciation

    static int instCount = 0;

    public FakeAutocompleteRepository()
    {
        instCount++;
        ...
    }

and running it all in debug. Indeed the second time I do a composition I get a new copy of the FakeAutocompleteRepository with instCount = 2. The export section contains

[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(IAutocompleteRepository))]
[ExportMetadata("IsTesting", "True")]
class FakeAutocompleteRepository : IAutocompleteRepository
{ ... }

Is there some trick to getting the same instance for subsiquent requests? In case it is something I'm doing during the composition this is how I'm doing that

var catalog = new AggregateCatalog();
                catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
                catalog.Catalogs.Add(new DirectoryCatalog("."));
                var container = new CompositionContainer(catalog);
                var batch = new CompositionBatch();
                batch.AddPart(this);
                container.Compose(batch);


                if (null != ConfigurationSettings.AppSettings["IsTesting"] && bool.Parse(ConfigurationSettings.AppSettings["IsTesting"]))
                    repository = container.GetExports<IAutocompleteRepository>().Where(expDef => expDef.Metadata.Keys.Contains("IsTesting")).Single().GetExportedObject();

Basically I'm trying to force a specific composition during testing. If you have a better idea for unit testing these compositions then I'm all ears.

+2  A: 

I don't see anything specifically in your code that would cause more than one of your part to be created. Are you creating a different container for each composition? If you are, that is why you are getting separate instances.

As far as how to combine composition and unit testing in general, there is some discussion of this here.

Daniel Plaisted
I totally am creating a new container each time. Is there a way to query for active containers or should one create a per applications instance somewhere?
stimms
There isn't a way to query for active containers. I'd have to understand more about your application to give you advice on what you should do. What are the multiple compositions for?
Daniel Plaisted
What you can do is Export your container from your host, and import it every time you want to use it. I haven't done that, but I think I saw it in the MefShapes game example...
Scott Whitlock
+1  A: 

What I did for unit testing was avoid composition. For instance (I'm using WPF and MVVM here), let's say you want to test this ViewModel:

[Export("/MyViewModel")]
public class MyViewModel
{
    [ImportingConstructor]
    public MyViewModel(
        [Import("/Services/LoggingService")] ILoggingService l)
    {
        logger = l;
    }

    private ILoggingService logger { get; set; }

    /* ... */
}

I don't want to instantiate the full-blown logging service every time I do a unit test, so I have a MockLoggingService class that implements ILoggingService and it just swallows all the log messages, (or checks that the proper messages are being generated, if you care). Then I can do this in my unit test:

MyViewModel target = new MyViewModel(new MockLoggingService());
Scott Whitlock