c# – 如何将Fitnesse与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,Object[] activationAttributes)
   at System.Reflection.Assembly.CreateInstance(String typeName,Boolean ignoreCase,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,CultureInfo culture)
   at System.RuntimeType.InvokeMember(String name,BindingFlags bindingFlags,Object target,Object[] providedArgs,ParameterModifier[] modifiers,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)

编辑:非常感谢迈克,现在正在努力享受.

实现非常简单,我确信它可以改进,但这里有一个快速方法

>定义自定义CreateOperator
>创建SuiteConfig.xml以指向dll并加载自定义create运算符
>启动跑步者时指定SuiteConfig
>注册灯具

我的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,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,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);
        }
    }
}

相关文章

目录简介使用JS互操作使用ClipLazor库创建项目使用方法简单测...
目录简介快速入门安装 NuGet 包实体类User数据库类DbFactory...
本文实现一个简单的配置类,原理比较简单,适用于一些小型项...
C#中Description特性主要用于枚举和属性,方法比较简单,记录...
[TOC] # 原理简介 本文参考[C#/WPF/WinForm/程序实现软件开机...
目录简介获取 HTML 文档解析 HTML 文档测试补充:使用 CSS 选...