plugins - 自定义 SpecFlow TestGeneratorProvider 注册在测试生成时导致 NullReferenceException

标签 plugins configuration-files nullreferenceexception specflow

我正在尝试在 SpecFlow 1.9 中添加我的 CodedUI 测试生成器插件。我正在尝试使用新的插件注册,因为旧类型的注册会导致我们的解决方案中出现各种问题,因为我们不想将自定义生成器提供程序放在 Specflow 安装目录中(每个开发人员机器上都不同) .

我开始添加新的 Specflow.CustomPlugin NuGet package到 .NET 4.0 类库。

根据 CodedUI Generator 的示例,我将其拼凑在一起:

using TechTalk.SpecFlow.Infrastructure;
[assembly: GeneratorPlugin(typeof(CodedUIGeneratorProvider.Generator.SpecFlowPlugin.CodedUIGeneratorPlugin))]

namespace CodedUIGeneratorProvider.Generator.SpecFlowPlugin
{
    using System.CodeDom;

    using BoDi;

    using TechTalk.SpecFlow.Generator;
    using TechTalk.SpecFlow.Generator.Configuration;
    using TechTalk.SpecFlow.Generator.Plugins;
    using TechTalk.SpecFlow.Generator.UnitTestProvider;
    using TechTalk.SpecFlow.UnitTestProvider;
    using TechTalk.SpecFlow.Utils;

    /// <summary>
    /// The CodedUI generator plugin.
    /// </summary>
    public class CodedUIGeneratorPlugin : IGeneratorPlugin
    {
        /// <summary>
        /// The register dependencies.
        /// </summary>
        /// <param name="container">
        /// The container.
        /// </param>
        public void RegisterDependencies(ObjectContainer container)
        {
        }

        /// <summary>
        /// The register customizations.
        /// </summary>
        /// <param name="container">
        /// The container.
        /// </param>
        /// <param name="generatorConfiguration">
        /// The generator configuration.
        /// </param>
        public void RegisterCustomizations(ObjectContainer container, SpecFlowProjectConfiguration generatorConfiguration)
        {
            container.RegisterTypeAs<CodedUIGeneratorProvider, IUnitTestGeneratorProvider>("default");
            container.RegisterTypeAs<MsTest2010RuntimeProvider, IUnitTestRuntimeProvider>("default");
        }

        /// <summary>
        /// The register configuration defaults.
        /// </summary>
        /// <param name="specFlowConfiguration">
        /// The spec flow configuration.
        /// </param>
        public void RegisterConfigurationDefaults(SpecFlowProjectConfiguration specFlowConfiguration)
        {
        }
    }

    /// <summary>
    /// The CodedUI generator.
    /// </summary>
    public class CodedUIGeneratorProvider : MsTest2010GeneratorProvider
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CodedUiGeneratorProvider"/> class.
        /// </summary>
        /// <param name="codeDomHelper">
        /// The code dom helper.
        /// </param>
        public CodedUIGeneratorProvider(CodeDomHelper codeDomHelper)
            : base(codeDomHelper)
        {
        }

        /// <summary>
        /// The set test class.
        /// </summary>
        /// <param name="generationContext">
        /// The generation context.
        /// </param>
        /// <param name="featureTitle">
        /// The feature title.
        /// </param>
        /// <param name="featureDescription">
        /// The feature description.
        /// </param>
        public override void SetTestClass(TestClassGenerationContext generationContext, string featureTitle, string featureDescription)
        {
            base.SetTestClass(generationContext, featureTitle, featureDescription);

            foreach (CodeAttributeDeclaration declaration in generationContext.TestClass.CustomAttributes)
            {
                if (declaration.Name == "Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute")
                {
                    generationContext.TestClass.CustomAttributes.Remove(declaration);
                    break;
                }
            }

            generationContext.TestClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference("Microsoft.VisualStudio.TestTools.UITesting.CodedUITestAttribute")));
        }
    }
}

当尝试按如下方式配置它时:
  <specFlow>
    <!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
    <plugins>
      <add name="CodedUIGeneratorProvider" path="." type="GeneratorAndRuntime"/>
    </plugins>
    <generator dependencies="CodedUIGeneratorProvider"/>
    <runtime dependencies="CodedUIGeneratorProvider"/>
  </specFlow>

我收到以下错误消息:

error Generation error: SpecFlow configuration error -> The value of the property 'dependencies' cannot be parsed. The error is: Object reference not set to an instance of an object.



该错误似乎是在 SpecFlow 配置代码内部引起的,堆栈跟踪如下:
 System.Configuration.dll!System.Configuration.ConfigurationProperty.ConvertFromString(string value) + 0x2a bytes
 System.Configuration.dll!System.Configuration.ConfigurationElement.DeserializePropertyValue(System.Configuration.ConfigurationProperty prop, System.Xml.XmlReader reader) + 0x36 bytes
 System.Configuration.dll!System.Configuration.ConfigurationElement.DeserializeElement(System.Xml.XmlReader reader, bool serializeCollectionKey) + 0x221 bytes
 System.Configuration.dll!System.Configuration.ConfigurationElement.DeserializeElement(System.Xml.XmlReader reader, bool serializeCollectionKey) + 0x78e bytes
 System.Configuration.dll!System.Configuration.ConfigurationSection.DeserializeSection(System.Xml.XmlReader reader) + 0x3c bytes
 TechTalk.SpecFlow.dll!TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler.CreateFromXml(string xmlContent) + 0xb0 bytes
 TechTalk.SpecFlow.Generator.dll!TechTalk.SpecFlow.Generator.Configuration.GeneratorConfigurationProvider.LoadConfiguration(TechTalk.SpecFlow.Generator.Interfaces.SpecFlowConfigurationHolder configurationHolder, TechTalk.SpecFlow.Generator.Configuration.SpecFlowProjectConfiguration configuration) + 0x41 bytes
 TechTalk.SpecFlow.Vs2010Integration.dll!TechTalk.SpecFlow.Vs2010Integration.Generator.VsGeneratorInfoProvider.GenGeneratorConfig() + 0x52 bytes
 TechTalk.SpecFlow.Vs2010Integration.dll!TechTalk.SpecFlow.Vs2010Integration.Generator.VsGeneratorInfoProvider.GetGeneratorInfo() + 0x3a bytes
 TechTalk.SpecFlow.IdeIntegration.dll!TechTalk.SpecFlow.IdeIntegration.Generator.RemoteGeneratorServices.GetGeneratorInfo() Line 38 + 0x9 bytesC#
 TechTalk.SpecFlow.IdeIntegration.dll!TechTalk.SpecFlow.IdeIntegration.Generator.RemoteGeneratorServices.GetTestGeneratorFactoryForCreate() Line 43 + 0xa bytesC#
 TechTalk.SpecFlow.IdeIntegration.dll!TechTalk.SpecFlow.IdeIntegration.Generator.GeneratorServices.CreateTestGenerator() Line 24 + 0xa bytesC#
 TechTalk.SpecFlow.IdeIntegration.dll!TechTalk.SpecFlow.IdeIntegration.Generator.IdeSingleFileGenerator.GenerateCode(string inputFilePath, string inputFileContent,  TechTalk.SpecFlow.IdeIntegration.Generator.GeneratorServices generatorServices, TechTalk.SpecFlow.Generator.Interfaces.ProjectSettings projectSettings) Line 38 + 0x29 bytesC#
 TechTalk.SpecFlow.IdeIntegration.dll!TechTalk.SpecFlow.IdeIntegration.Generator.IdeSingleFileGenerator.Generate(string inputFilePath, string inputFileContent,  TechTalk.SpecFlow.IdeIntegration.Generator.GeneratorServices generatorServices, TechTalk.SpecFlow.Utils.CodeDomHelper codeDomHelper,  TechTalk.SpecFlow.Generator.Interfaces.ProjectSettings projectSettings) Line 23 + 0x12 bytesC#
 TechTalk.SpecFlow.IdeIntegration.dll!TechTalk.SpecFlow.IdeIntegration.Generator.IdeSingleFileGenerator.GenerateFile(string inputFilePath, string outputFilePath,  System.Func<TechTalk.SpecFlow.IdeIntegration.Generator.GeneratorServices> generatorServicesProvider, System.Func<string,string> inputFileContentProvider,  System.Action<string,string> outputFileContentWriter) Line 92 + 0x13 bytesC#
 TechTalk.SpecFlow.Vs2010Integration.dll!TechTalk.SpecFlow.VsIntegration.SingleFileGenerator.SpecFlowSingleFileGeneratorBase.GenerateInternal(string inputFilePath, string inputFileContent, EnvDTE.Project project, string defaultNamespace, System.Action<TechTalk.SpecFlow.VsIntegration.SingleFileGenerator.SingleFileGeneratorError> onError, out string generatedContent) + 0x18e bytes
 TechTalk.SpecFlow.Vs2010Integration.dll!TechTalk.SpecFlow.VsIntegration.SingleFileGenerator.SingleFileGeneratorBase.Generate(string inputFilePath, string inputFileContents, string defaultNamespace, System.IntPtr[] rgbOutputFileContents, out uint pcbOutput, Microsoft.VisualStudio.Shell.Interop.IVsGeneratorProgress generateProgress) + 0xc3 bytes
 [Native to Managed Transition]

哪个反射器告诉我只能表示TechTalk.SpecFlow.IdeIntegration.Generator.RemoteGeneratorServices.generatorInfoProvidernull .

我不知道如何解决这个问题。很少有文档可以解决这个问题。

问题:

如果我能让这个工作,我会很高兴。或者,我希望看到一种无需将文件放入 SpecFlow 安装目录即可配置“旧方式”的方法。

最佳答案

我发现了这个问题:)

在插件的注册自定义方法中,不要使用名称注册,只需使用 RegisterTypeAs方法:

public void RegisterCustomizations(ObjectContainer container, SpecFlowProjectConfiguration generatorConfiguration)
{
    container.RegisterTypeAs<CodedUIGeneratorProvider, IUnitTestGeneratorProvider>();
}

然后配置看起来很简单,像这样:
<specFlow>
  <!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
  <plugins>
    <add name="CodedUIGeneratorProvider" path="." type="Generator"/>
  </plugins>
</specFlow>

通过这种方式,您可以将插件程序集(必须命名为 *.SpecflowPlugin.dll)放到项目目录中,或者使用项目目录中的相对路径并将其设置在 path=".\Lib" 中。 plugins\add 的属性(property)元素。

更多信息请参见:https://jessehouwing.net/specflow-custom-unit-test-generator/

关于plugins - 自定义 SpecFlow TestGeneratorProvider 注册在测试生成时导致 NullReferenceException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16222579/

相关文章:

Grails 远程分页正在刷新整个页面而不是 div

grails - 如何从.zip安装自定义Grails插件?

plugins - 为小程序使用特定的 jre

javascript - order.before : 的 Brunch.io brunch-config.js 语义

c# - 如何处理 NullReference 异常 C#

ruby-on-rails - jRails 替代品

c - 避免在 C 中读取配置文件的全局变量

linux - 配置文件中的文件名应该使用绝对路径还是相对路径?

java - Android JSONParser 中的 NullPointerException

c# - 如何测试 Action<...> 是否为空?