TotalTest / SpecFlow.Contrib.Variants

SpecFlow plugin to allow variants of a test to be run using tags e.g. against different browsers
MIT License
3 stars 8 forks source link

Could not load TechTalk.SpecFlow.Generator #6

Closed modmoto closed 1 year ago

modmoto commented 2 years ago

We wanted to use your plugin together with xunit, playwright and net6 and the scenario generation for multiple tests works well, but as soon as I run a test, I get this error when I start the virtual service.

One or more errors occurred. (Unable to load one or more of the requested types.
Could not load file or assembly 'TechTalk.SpecFlow.Generator, Version=3.9.0.0, Culture=neutral, PublicKeyToken=0778194805d6db41'. The system cannot find the file specified.

I can not seam to find this nuget or a class of it anywhere. I also found some issues on SO that mention to rebuild and reinstall the nuget but all of that did not help. Does someone else also have this issue and could point me to a solution? It feels like some nuspec is configured wrong... If I uninstall the dependency to SpecFlow.Contrib.Variants the test cases dont work anymore but the I do not the the exception above.

modmoto commented 2 years ago

I could fix this by adding the SpecFlow.CustomPlugin reference to the project. If this is needed, should this not be in the nuspec to get this transient dependency?

TotalTest commented 2 years ago

This is odd, I have created a project in net6 using xunit and the SpecFlow.Contrib.Variants and the tests are running fine.

I have attached two images, one shows the list of dependencies and the other the csproj file. It's worth comparing with yours to see if anything stands out. If there's nothing obvious you can send me a zip of your project to and I'll attempt to debug.

Csproj Deps

modmoto commented 2 years ago

I sadly can not send you the project as this is a company project. But I can give you the factory that we use to init the service.

public class PlaywrightTestServerFactory : WebApplicationFactory<ApiStartup>
        {
            private const string _LocalhostBaseAddress = "https://localhost";

            private IWebHost _host;

            /// <summary>
            /// Initializes a new instance of the <see cref="PlaywrightTestServerFactory"/> class.
            /// Creates a new WebApplication Factory with environment, logging and webhost override.
            /// </summary>
            public PlaywrightTestServerFactory()
            {
                ClientOptions.BaseAddress = new Uri(_LocalhostBaseAddress);
                CreateServer(CreateWebHostBuilder());
            }

            public string RootUri { get; private set; }

            protected override TestServer CreateServer(IWebHostBuilder builder)
            {
                // Load server URL from hosting.json file so that the web server runs on the correct port for testing.
                var config = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("Configuration/appsettings.json", optional: false)
                    .Build();

                try
                {
                    _host = builder
                        .UseConfiguration(config)
                        .Build();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }

                _host.Start();

                RootUri = _host.ServerFeatures.Get<IServerAddressesFeature>().Addresses.LastOrDefault();

                // There doesn't seem to be a need to return a test server instance.  If so it would be different to what is created previously.
                // Attempting to use the same instance causes errors, creating new instances creates slightly different web servers.
                return null;
            }

            protected override IWebHostBuilder CreateWebHostBuilder()
            {
                var builder = WebHost.CreateDefaultBuilder(Array.Empty<string>());

                builder.UseStartup<ApiStartup>();

                return builder;
            }

            [ExcludeFromCodeCoverage]
            protected override void Dispose(bool disposing)
            {
                base.Dispose(disposing);
                if (disposing)
                {
                    _host?.Dispose();
                }
            }
        }

The exception gets thrown on

_host = builder
        .UseConfiguration(config)
        .Build();

You do reference SpecFlow.CustomPlugin though but when installing it does not seam to pull the nuget aswell. I guess the project does not build anymore when you remove that reference, right? In your example project, do you get the SpecFlow.CustomPlugin.dll in the bin folder? Might be that you are hitting some code that does not need the dll and therefore works.

TotalTest commented 2 years ago

SpecFlow.CustomPlugin.dll is not in the bin folder, it's only needed for the development of specflow plugins as opposed to the consumption of them (you can see the Specflow.xUnit plugin's nuspec file as an example: https://github.com/SpecFlowOSS/SpecFlow/blob/master/Plugins/TechTalk.SpecFlow.xUnit.Generator.SpecFlowPlugin/SpecFlow.xUnit.nuspec)

Just to confirm this plugin is only for generation, i.e. when you build the project the *.feature.cs file is created and this specific plugin works with that file. This plugin isn't used during the execution, or runtime, of the test.

Are you referencing any other specflow runtime plugins? And also worth confirming the versions of all specflow nuget packages and ensuring they are the same.

modmoto commented 2 years ago

No, those are the only specflow plugins that I reference

<PackageReference Include="SpecFlow" Version="3.9.74" />
<PackageReference Include="SpecFlow.Contrib.Variants" Version="3.9.74" />
<PackageReference Include="SpecFlow.CustomPlugin" Version="3.9.74" />
<PackageReference Include="SpecFlow.Plus.LivingDocPlugin" Version="3.9.57" />
<PackageReference Include="SpecFlow.xUnit" Version="3.9.74" />

and SpecFlow.CustomPlugin is only there to make SpecFlow.Contrib.Variants works. I know that this seams to only be needed for the build, but are you sure that you do not reference anything of this dll during runtime? Maybe some injection that gets resolved when I start the service and then the class can not be resolved.

To be fair, this is actually fine for me as I have a workaround, but it definitly would be cleaner to get rid of this reference. Also maybe someone else has this issus and finds this solution here.

And also thanks a lot for the plugin, it is working great for us!

TotalTest commented 1 year ago

Hi @modmoto, sorry for going quite on this. Re-visiting this I noticed that the SpecFlow.Tools.MsBuild.Generation package wasn't included in the plugin (similar to other generator plugins from Specflow have it). I can't prove this will sort your issue as I couldn't reproduce the original error but feel free to try the latest pre-release version (3.9.80-pre.1) to see if you get better luck.