jcansdale / TestDriven.Net-Issues

Issue tracking for TestDriven.Net
https://github.com/jcansdale/TestDriven.Net-Issues/issues
24 stars 2 forks source link

Allow targeting of MEF components with new dependencies #132

Closed jcansdale closed 6 years ago

jcansdale commented 6 years ago

TestDriven.Net currently supports targeting a MEF components with dependencies that are already active inside Visual Studio. If however we target a component with a new dependency, the newly added component wont be found and the execution will fail.

For example:

Targeting the ExecuteAsync method:

    using System;
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Editor;
    using Microsoft.VisualStudio.TextManager.Interop;
    using Task = System.Threading.Tasks.Task;
    using Microsoft.VisualStudio;

    [Export(typeof(YourCommand))]
    public class YourCommand
    {
        readonly IVsEditorAdaptersFactoryService adapters;
        readonly ITextManagerService textManager;

        [ImportingConstructor]
        public YourCommand(
            IVsEditorAdaptersFactoryService adapters,
            ITextManagerService textManager)
        {
            this.adapters = adapters;
            this.textManager = textManager;
        }

        public async Task ExecuteAsync()
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            var textView = textManager.GetActiveView();
            var wpfTextView = adapters.GetWpfTextView(textView);
            var options = wpfTextView.Options;
            foreach (var option in options.SupportedOptions)
            {
                Console.WriteLine($"{option.Name}: {options.GetOptionValue(option.Name)}");
            }
        }
    }

    public interface ITextManagerService
    {
        IVsTextView GetActiveView();
    }

    [Export(typeof(ITextManagerService))]
    public class TextManagerService : ITextManagerService
    {
        readonly Lazy<IVsTextManager> textManager;

        [ImportingConstructor]
        public TextManagerService(
            [Import(typeof(SVsServiceProvider))] IServiceProvider sp)
        {
            textManager = new Lazy<IVsTextManager>(() => (IVsTextManager)sp.GetService(typeof(SVsTextManager)));
        }

        public IVsTextView GetActiveView()
        {
            ErrorHandler.ThrowOnFailure(textManager.Value.GetActiveView(1, null, out IVsTextView textView));
            return textView;
        }
    }

Will fail with:

Test 'M:PrototypeMef.YourCommand.ExecuteAsync' failed: No exports were found that match the constraint: 
    ContractName    PrototypeMef.YourCommand
    RequiredTypeIdentity    
    System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint:
        ContractName    PrototypeMef.YourCommand
        RequiredTypeIdentity
    at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
    at System.ComponentModel.Composition.Hosting.ExportProvider.GetExportsCore(Type type, Type metadataViewType, String contractName, ImportCardinality cardinality)
    at System.ComponentModel.Composition.Hosting.ExportProvider.GetExportedValueCore[T](String contractName, ImportCardinality cardinality)
    at System.ComponentModel.Composition.Hosting.ExportProvider.GetExportedValue[T](String contractName)
    at TestDriven.TestRunner.Server.ImportArgumentFactory.TryGetTargetObject(Type targetType)
    at TestDriven.TestRunner.Server.ServiceAdHocDefaults.GetTargetObject(Type targetType)
    at TestDriven.TestRunner.Server.AsyncMemberTestRunner.<RunMemberAsync>d__5.MoveNext()

This isn't very helpful. 😢