SpecFlowOSS / SpecFlow

#1 .NET BDD Framework. SpecFlow automates your testing & works with your existing code. Find Bugs before they happen. Behavior Driven Development helps developers, testers, and business representatives to get a better understanding of their collaboration
https://www.specflow.org/
Other
2.25k stars 754 forks source link

IOException during feature MSbuild generation when using multiple target frameworks #2713

Open JulienKappa opened 1 year ago

JulienKappa commented 1 year ago

SpecFlow Version

4.0.31-beta

Which test runner are you using?

xUnit

Test Runner Version Number

2.5.0

.NET Implementation

.NET 6.0

Project Format of the SpecFlow project

Sdk-style project format

.feature.cs files are generated using

SpecFlow.Tools.MsBuild.Generation NuGet package

Test Execution Method

Visual Studio Test Explorer

SpecFlow Section in app.config or content of specflow.json

{ "$schema": "https://specflow.org/specflow-config.json", "stepAssemblies": [ { "assembly": "Core.IT.Bindings" }, { "assembly": "FTA.Integration.Analysis.Specflow.Bindings" } ],

"runtime": {
    "missingOrPendingStepsOutcome": "Inconclusive",
    "stopAtFirstError": true
},

"trace": {
    "traceSuccessfulSteps": true,
    "traceTimings": true,
    "minTracedDuration": "0:0:0.0",
    "stepDefinitionSkeletonStyle": "RegexAttribute"
}

}

Issue Description

Hi,

We have been using Specflow for some years now. We have updated our projects to SDK and we use multiple target frameworks :

net462;net6.0

Feature code is generated twice (one time per framework).

We encounter IOExceptions as net462 / net6 builds are done in parallel and the file is being overwritten while still in use by the first one (for compilation)... It can happen more or less randomly, depending on the project. I was not able to reproduce using the tutorial project (Calculator...), using multiple frameworks, it seems generation is done twice also but without problem. Any idea on how to solve this?

Here is the exception :

D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : [SpecFlow] System.IO.IOException: The process cannot access the file 'D:\dev5.0_GIT\pl\FTA.Integration.A nalysis.Specflow_IT\Features\Analysis.feature.cs' because it is being used by another process. [D:\dev5.0_GIT\pl\FTA.In tegration.Analysis.Specflow_IT\FTA.Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at System.IO._Error.WinIOError(Int32 errorCode, String maybeFullPath) [D:\dev5.0_GIT\pl\FTA.Integrat ion.Analysis.Specflow_IT\FTA.Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean use Rights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean b FromProxy, Boolean useLongPath, Boolean checkHost) [D:\dev5.0_GIT\pl\FTA.Integration.Analysis.Specflow_IT\FTA.Integrati on.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 b ufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) [D:\dev5.0 GIT\pl\FTA.Integration.Analysis.Specflow_IT\FTA.Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMa rks, Int32 bufferSize, Boolean checkHost) [D:\dev5.0_GIT\pl\FTA.Integration.Analysis.Specflow_IT\FTA.Integration.Analys is.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at System.IO.File.InternalReadAllText(String path, Encoding encoding, Boolean checkHost) [D:\dev5.0_G IT\pl\FTA.Integration.Analysis.Specflow_IT\FTA.Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at SpecFlow.Tools.MsBuild.Generation.CodeBehindWriter.WriteCodeBehindFile(String outputPath, String f eatureFile, TestFileGeneratorResult testFileGeneratorResult) [D:\dev5.0_GIT\pl\FTA.Integration.Analysis.Specflow_IT\FTA .Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at SpecFlow.Tools.MsBuild.Generation.FeatureFileCodeBehindGenerator.d__6.Mov eNext() [D:\dev5.0_GIT\pl\FTA.Integration.Analysis.Specflow_IT\FTA.Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() [D:\dev5.0_GIT\pl\FTA.Integratio n.Analysis.Specflow_IT\FTA.Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at System.Linq.Buffer1..ctor(IEnumerable1 source) [D:\dev5.0_GIT\pl\FTA.Integration.Analysis.Specfl ow_IT\FTA.Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source) [D:\dev5.0_GIT\pl\FTA.Integration.An alysis.Specflow_IT\FTA.Integration.Analysis.Specflow_IT.csproj] D:\dev5.0_GIT\pl\Packages\specflow.tools.msbuild.generation\4.0.7-beta\build\SpecFlow.Tools.MsBuild.Generation.targets( 93,5): error : at SpecFlow.Tools.MsBuild.Generation.GenerateFeatureFileCodeBehindTaskExecutor.Execute() [D:\dev5.0_G IT\pl\FTA.Integration.Analysis.Specflow_IT\FTA.Integration.Analysis.Specflow_IT.csproj]

Thanks,

Regards,

Julien

Steps to Reproduce

Was not able to reproduce on a sample project. I tried modifying the tutorial with calculator to add multiple targetframeworks, generation is done twice but no write error...

Link to Repro Project

No response

JulienKappa commented 1 year ago

My only find is that the hook is generated in a targetframework specific folder, not the feature.cs. Is there a way to generated feature.cs in targetframework specific folders?

image

image

JulienKappa commented 1 year ago

I found a workaround, if we put <BuildInParallel>false</BuildInParallel> in the csproj, it works (target frameworks are processed one by one). Maybe this property can be added to the props in the SpecFlow.Tools.MsBuild.Generation nuget?

icnocop commented 11 months ago

I don't think we should disable parallel builds.

What's happening is the code behind files (*.feature.cs) are being re-generated multiple times, once for each target framework.

Instead, I think the code behind files (*.feature.cs) should be generated once for all target frameworks.

I've read that one way to do this is to schedule the code generation target so that it runs before the DispatchToInnerBuilds target.

For example,

<Target Name="UpdateFeatureFilesInProject"
          BeforeTargets="DispatchToInnerBuilds"
          DependsOnTargets="BeforeUpdateFeatureFilesInProject">

But I haven't tested this.