簡體   English   中英

如何將Fitnesse與Autofac / IOC集成?

[英]How to integrate Fitnesse with Autofac/IOC?

當Fitnesse實例化一個fixture時,它會查找默認的公共構造函數。

但是,我想構造函數注入我想要在fixture中使用的任何應用程序服務。

即我想寫這個夾具...

public class MyColumnFixture : ColumnFixture {
    private readonly IApplicationService _applicationService;

    public ManualExitSetupFixture(IApplicationService applicationService) {
        _applicationService = applicationService;
    }

    public void DoStuff(string arg1) {
        _applicationService.DoStuff(arg1);
    }
}

到目前為止,我設法提出的最好的方法是將容器暴露為單例(見下文)。 但必須有更好的方法 Autofac與我們使用的許多其他技術完美集成。

public class AutofacIntegration {
    private static IContainer _container;

    public static IContainer Container {
        get {
           if (_container == null) {
              var builder = new ContainerBuilder();
              builder.RegisterModule<MyApplicationModule>();
               _container = builder.Build();                    
           }
           return _container;
         }
    }
}

public class MyColumnFixture : ColumnFixture {
    private readonly IApplicationService _applicationService;

    public ManualExitSetupFixture() {
        _applicationService = AutofacIntegration.Container.Resolve<IApplicationService>();
    }

    public void DoStuff(string arg1) {
        _applicationService.DoStuff(arg1);
    }
}

編輯:包括更多細節,我試圖在Mike的幫助下完成這項工作......

我創建了一個類,它是從Fitsharp反編譯的CreateDefault的反編譯代碼中復制粘貼的...

public class CreateDefault<T, P> : Operator<T, P>, CreateOperator<T> where P : class, Processor<T>
{
    public bool CanCreate(NameMatcher memberName, Tree<T> parameters)
    {
        return true;
    }

    public TypedValue Create(NameMatcher memberName, Tree<T> parameters)
    {
        ...
    }
}

...並在SuiteConfig.xml中注冊了這個...

<suiteConfig>
    <ApplicationUnderTest>
        <AddAssembly>..\..\Services\Win\MyProj.Fitnesse\MyProj.Fitnesse\bin\Debug\MyProj.Fitnesse.dll</AddAssembly>
     </ApplicationUnderTest>
     <Fit.Operators>
         <Add>MyProj.Fitnesse.CreateDefault`2</Add>
     </Fit.Operators>
</suiteConfig>

...當它嘗試加載我的CreateDefault <,>類時,會出現以下異常。

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> fitSharp.Machine.Exception.CreateException: Constructor with 0 parameter(s) failed for type 'MyProj.Fitnesse.CreateDefault`2'. ---> System.ArgumentException: Cannot create an instance of MyProj.Fitnesse.CreateDefault`2[T,P] because Type.ContainsGenericParameters is true.
   at System.RuntimeType.CreateInstanceCheckThis()
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Reflection.Assembly.CreateInstance(String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at fitSharp.Machine.Engine.RuntimeType.CreateInstance()
   at fitSharp.Machine.Engine.CreateDefault`2.CreateWithoutParameters(RuntimeType runtimeType)
   --- End of inner exception stack trace ---
   at fitSharp.Machine.Engine.CreateDefault`2.CreateWithoutParameters(RuntimeType runtimeType)
   at fitSharp.Machine.Engine.CreateDefault`2.Create(NameMatcher memberName, Tree`1 parameters)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
   at fitSharp.Machine.Engine.MethodMember.TryInvoke(Object[] parameters)
   at fitSharp.Machine.Engine.ReflectionMember.Invoke(Object[] parameters)
   at fitSharp.Machine.Engine.ProcessorBase`2.Operate[O](Object[] parameters)
   at fitSharp.Machine.Engine.Operators`2.Add(String operatorName)
   --- End of inner exception stack trace ---
   at fitSharp.Machine.Engine.ProcessorExtension.InvokeWithThrow[T](Processor`1 processor, TypedValue instance, MemberName memberName, Tree`1 parameters)
   at fitSharp.Machine.Application.SuiteConfiguration.LoadNode(String typeName, XmlNode methodNode)
   at fitSharp.Machine.Application.SuiteConfiguration.LoadXml(String configurationXml)
   at fitSharp.Machine.Application.ArgumentParser.InvokeArgumentHandler(String switch, String argumentValue)
   at fitSharp.Machine.Application.ArgumentParser.Parse(IList`1 commandLineArguments)
   at fitSharp.Machine.Application.Shell.Run(IList`1 commandLineArguments)

編輯:非常感謝邁克,現在正在努力享受。

實現非常簡單,我確信它可以改進,但這里有一個快速的方法...

  1. 定義自定義CreateOperator
  2. 創建SuiteConfig.xml以指向dll並加載自定義create運算符
  3. 啟動跑步者時指定SuiteConfig
  4. 注冊燈具

我的CreateOperator代碼......

public class AutofacCreateOperator : CellOperator, CreateOperator<Cell>
{
    private static IContainer _container;

    public AutofacCreateOperator()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<FitnesseModule>();
        _container = builder.Build();
    }

    public bool CanCreate(NameMatcher memberName, Tree<Cell> parameters)
    {
        return _container.ComponentRegistry.IsRegistered(new TypedService(Type.GetType(memberName.MatchName)));
    }

    public TypedValue Create(NameMatcher memberName, Tree<Cell> parameters)
    {
        return new TypedValue(_container.Resolve(Type.GetType(memberName.MatchName)));
    }
}

這可以完成 - 您需要編寫一個自定義類來處理fitSharp的創建操作。 它將實現此接口:

public interface CreateOperator<T> {
    bool CanCreate(NameMatcher memberName, Tree<T> parameters);
    TypedValue Create(NameMatcher memberName, Tree<T> parameters);
}

然后告訴fitSharp在套件配置文件中使用此類:

<suiteConfig>
    <Fit.Operators>
        <Add>My.Create.Operator</Add>
    </Fit.Operators>
    ...
</suiteConfig>

作為一個說明點,這是一個非常簡單的創建運算符。 你可以修改它來進行AutoFac注入。

public class TestCreateOperator: CellOperator, CreateOperator<Cell> {
  public bool CanCreate(NameMatcher memberName, Tree<Cell> parameters) {
    return memberName.Matches("testname");
  }
  public TypedValue Create(NameMatcher memberName, Tree<Cell> parameters) {
    return new TypedValue("mytestname");
  }
}

僅供參考,這是內置類,用於創建夾具。

public class CreateDefault<T,P>: Operator<T, P>, CreateOperator<T> where P: class, Processor<T> {
    public bool CanCreate(NameMatcher memberName, Tree<T> parameters) {
        return true;
    }

public TypedValue Create(NameMatcher memberName, Tree<T> parameters) {
    var runtimeType = Processor.ApplicationUnderTest.FindType(memberName);
    return parameters.Branches.Count == 0
                 ? CreateWithoutParameters(runtimeType)
                 : CreateWithParameters(parameters, runtimeType);
}

static TypedValue CreateWithoutParameters(RuntimeType runtimeType) {
    try {
        return runtimeType.CreateInstance();
    }
    catch (System.Exception e) {
        throw new CreateException(runtimeType.Type, 0, e.InnerException ?? e);
    }
}

TypedValue CreateWithParameters(Tree<T> parameters, RuntimeType runtimeType) {
    RuntimeMember member = runtimeType.GetConstructor(parameters.Branches.Count);
    object[] parameterList = new ParameterList<T>(Processor).GetParameterList(TypedValue.Void, parameters, member);
        try {
            return member.Invoke(parameterList);
        }
        catch (System.Exception e) {
            throw new CreateException(runtimeType.Type, parameterList.Length, e.InnerException ?? e);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM