microsoft / testfx

MSTest framework and adapter

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

3.4 is not working with Fakes

Evangelink opened this issue · comments

3.4.0 and 3.4.1 are both not working while 3.3.1 was fine for this scenario:

  • .NET8 ProjectX
  • .NET8 test ProjectY which uses Microsoft Fakes for project X
  • Build on Azure DevOps using VSBuild@1.
  • Run ProjectY

The Fakes assemblies cannot be resolved, each test that uses them outputs:

System.IO.FileNotFoundException: Could not load file or assembly 'ProjectX.Fakes, Version=x.x.x.x, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified..

Where ProjectX.Fakes.dll is present in the output folder next to ProjectY.exe.

Originally posted by @Rans4ckeR in #2922 (comment)

Could you please provide some more details? Are you using VSTest or MSTest runner to run the tests? Is the issue happening only on VS? Would it be possible for you to create a small reproducer?

cc @drognanar @jakubch1

Could you please provide some more details? Are you using VSTest or MSTest runner to run the tests? Is the issue happening only on VS? Would it be possible for you to create a small reproducer?

cc @drognanar @jakubch1

I can only reproduce it on Azure DevOps, not locally;

Pipeline bits

pool:
  vmImage: 'windows-2022'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'
  Agent.Source.Git.ShallowFetchDepth: 0

steps:
- task: UseDotNet@2
  inputs:
    packageType: 'sdk'
    version: '8.x'

- task: VSBuild@1
  displayName: 'Build Solution'
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'
    maximumCpuCount: true
    msbuildArchitecture: 'x64'

- task: CmdLine@2
  displayName: 'Run tests'
  inputs:
    script: '.\TestProject\bin\Release\net8.0\TestProject.exe --report-trx --coverage'

ProjectX

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
  <ItemGroup>
    <InternalsVisibleTo Include="TestProject" />
    <InternalsVisibleTo Include="ProjectX.Fakes" />
  </ItemGroup>
</Project>

TestProject

<Project Sdk="MSTest.Sdk/3.4.1">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
  <ItemGroup>
    <Compile Remove="FakesAssemblies\**" />
    <EmbeddedResource Remove="FakesAssemblies\**" />
    <None Remove="FakesAssemblies\**" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.QualityTools.Testing.Fakes" Version="17.5.0-beta.23060.1" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\ProjectX\ProjectX.csproj" />
  </ItemGroup>
  <ItemGroup>
    <AdditionalDesignTimeBuildInput Remove="FakesAssemblies\**" />
  </ItemGroup>
</Project>

TestProject\Fakes\ProjectX.fakes

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
  <Assembly Name="ProjectX"/>
  <StubGeneration>
    <Clear/>
    <Add Interfaces="true" Namespace="ProjectX!"/>
  </StubGeneration>
  <ShimGeneration Disable="true"/>
</Fakes>

If I build & run the tests locally in VS it works. Both running the tests in VS and running the .exe directly works.
If I copy the binaries produced from the pipeline to my local machine I get the same assembly resolution error.

Also tried this in the pipeline with the same result:

  • Use dotnet test instead of running the .exe
  • Downgrading Microsoft.QualityTools.Testing.Fakes to the latest stable
  • Target .NET9 instead of .NET8

what's the VS version on your local machine vs your CI? we recently updated the MSBuild props/targets files to include the Fakes dependencies in the executable's runtime configuration

with older VS versions, assembly resolution only works via vstest.console.exe, because it has a custom assembly resolver and picks up the Fakes assemblies regardless of the runtime configuration file content.

what's the VS version on your local machine vs your CI? we recently updated the MSBuild props/targets files to include the Fakes dependencies in the executable's runtime configuration

with older VS versions, assembly resolution only works via vstest.console.exe, because it has a custom assembly resolver and picks up the Fakes assemblies regardless of the runtime configuration file content.

On local machine 1 I have Microsoft Visual Studio Enterprise 2022 (64-bit) - Current Version 17.10.0
On local machine 2 I have Microsoft Visual Studio Enterprise 2022 (64-bit) - Preview Version 17.11.0 Preview 1.0
The CI machine, at the time of writing, has Visual Studio Enterprise 2022 | 17.9.34902.65

So it is expected that Fakes with 3.4.x does not work with VS <17.10 unless using VSTest@2?

Yes, that's expected.

You'd need to have a custom assembly resolver to resolve the dlls from .exe's folder without the correct runtime configuration.

Yes, that's expected.

You'd need to have a custom assembly resolver to resolve the dlls from .exe's folder without the correct runtime configuration.

So it's an undocumented breaking change, since 3.3.1 works fine?

if it's been working via a .exe already then there must be a change in how MSTest itself resolves assemblies

@Evangelink are you aware of any changes to assembly resolution in MSTest?

Outside of the bugs of 3.4.0 where the resolver wasn't triggered or the infinite recursion with resources not that I am aware of.

Outside of the bugs of 3.4.0 where the resolver wasn't triggered or the infinite recursion with resources not that I am aware of.

@Evangelink What infinite recursion with resources are you referring to? I couldn't find any related bug.
We are expiriencing a problem on Azure DevOps with

The active test run was aborted. Reason: Test host process crashed : Process terminated. Encountered infinite recursion while looking up resource 'Arg_NullReferenceException' in System.Private.CoreLib. Verify the installation of .NET is complete and does not need repairing, and that the state of the process has not become corrupted.

Both with MSTest 3.3.1 and 3.4.0. However I cannot directly relate it to MSTest

@Evangelink What infinite recursion with resources are you referring to? I couldn't find any related bug.

I am referring to #2692.

The active test run was aborted. Reason: Test host process crashed : Process terminated. Encountered infinite recursion while looking up resource 'Arg_NullReferenceException' in System.Private.CoreLib. Verify the installation of .NET is complete and does not need repairing, and that the state of the process has not become corrupted.

Could you please provide either a repro or diagnostic logs (see https://github.com/microsoft/vstest/blob/main/docs/diagnose.md)

@Evangelink What infinite recursion with resources are you referring to? I couldn't find any related bug.

I am referring to #2692.

Ok, that is a different one.

The active test run was aborted. Reason: Test host process crashed : Process terminated. Encountered infinite recursion while looking up resource 'Arg_NullReferenceException' in System.Private.CoreLib. Verify the installation of .NET is complete and does not need repairing, and that the state of the process has not become corrupted.

Could you please provide either a repro or diagnostic logs (see https://github.com/microsoft/vstest/blob/main/docs/diagnose.md)

If I can reproduce it reliably, I'll create an issue. Thanks.

Awesome, thank you @cbersch

So it is expected that Fakes with 3.4.x does not work with VS <17.10 unless using VSTest@2?

Yes, that's expected.

You'd need to have a custom assembly resolver to resolve the dlls from .exe's folder without the correct runtime configuration.

VS was updated to 17.10 by actions/runner-images#9965 but I still see an 'invalid' .exe being generated with 3.4.1 which can't resolve the Fakes assemblies.

if it's been working via a .exe already then there must be a change in how MSTest itself resolves assemblies

@Evangelink are you aware of any changes to assembly resolution in MSTest?

The .exe generated by 3.3.1 works fine on Azure DevOps with VS 17.10.

I just pushed a new package https://www.nuget.org/packages/Microsoft.Testing.Extensions.Fakes that should support Fakes and the new MSTest runner working side by side.

If you replace the existing Microsoft.QualityTools.Testing.Fakes package reference with the new extension reference it will pick up all of the environment variables as well as add the relevant instrumentation files to the bin folder to ensure that shims can be executed.

I just pushed a new package https://www.nuget.org/packages/Microsoft.Testing.Extensions.Fakes that should support Fakes and the new MSTest runner working side by side.

If you replace the existing Microsoft.QualityTools.Testing.Fakes package reference with the new extension reference it will pick up all of the environment variables as well as add the relevant instrumentation files to the bin folder to ensure that shims can be executed.

I think you forgot to push the dependency Microsoft.QualityTools.Testing.Fakes (>= 17.11.0-beta.24318.5)?

Thanks for letting me know.
Working on it right now, I need to update the version of the Microsoft.Testing.Platform that the package depends on as well. This requires building new packages.

Will update on the thread, once new packages are built and published.

Updated both of the packages

Updated both of the packages

The result seems to be the same with MSTest.Sdk/3.4.3 and Microsoft.Testing.Extensions.Fakes 17.11.0-beta.24319.3:

Unable to create instance of class TestClassY. Error: System.IO.FileNotFoundException: Could not load file or assembly 'XXX.Fakes, Version=x.x.x.x, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified..
Stack Trace:
at TestClassY..ctor()
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

MSTest.Sdk/3.3.1 and Microsoft.Testing.Extensions.Fakes 17.11.0-beta.24319.3 works fine.

Are you perhaps able to spin up an Azure DevOps build yourself and reproduce it?

I rolled back the targets file change locally and was able to reproduce it.

By bisecting the MSTest repo, the first package where this behaviour changed is this one #2654, so I'll let @Evangelink take a further look

@Rans4ckeR could you please confirm that when using a more recent version of VS the extension is working fine?

@Rans4ckeR could you please confirm that when using a more recent version of VS the extension is working fine?

When locally using VS 17.10 or VS 17.11 everything always works, regardless of the versions of any of the packages involved. Tests are running fine inside VS and tests are running fine when using the compiled .exe.

When compiling on Azure DevOps using VSBuild@1 the compiled .exe has different assembly probing logic than the one compiled locally. Only when reverting to MSTest.Sdk/3.3.1 the Azure DevOps .exe uses correct assembly probing.

The current runners on Azure DevOps are using VS 17.10.

The difference might be that VSBuild@1 is using MSBuild.exe while locally dotnet.exe is always used or something?

The difference might be that VSBuild@1 is using MSBuild.exe while locally dotnet.exe is always used or something?

I guess the difference is the version of MSBuild being inserted/available in dotnet SDK compared to the one in VS.

For the change in the version of MSTest. We introduced support of assembly resolution for .NET Core in #2110 but received many bugs related to this new feature as it's impacting how assemblies are being resolved by .NET so we decided to only plug the assembly resolver (for .NET Core) when user is asking for AssemblyResolution support in the .runsettings. This means that you ended up in the happy path of fakes working with MSTest 3.3 thanks to the assembly resolver although it wasn't designed for it. On MSTest 3.4+, we have this logic of using the resolver only when needed.

You will either need to wait for AzDO to contain the correct preview version of VS that contains the fix (@drognanar could you please confirm the version) or you will need to use AssemblyResolution functionality (https://learn.microsoft.com/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file#mstest-element) pointing to your bin folder.

The Fakes changes that makes Fakes assemblies load even without a custom assembly loader
have been merged in 17.11-preview 1.

Closing the issue as completed.