61

I have an ASP.NET Core Web API project targeting .NET Framework 4.7 that I'm trying to write integration tests for. I created a unit test project using Visual Studio Add new project and then the Unit Test Project (.NET Framework) template. I added the Microsoft.AspNetCore.Mvc.Testing NuGet package to the test project, and I have the following test:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestRepro.Tests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public async Task TestMethod1()
        {
            var factory = new WebApplicationFactory<Startup>();
            var client = factory.CreateClient();
            var response = await client.GetAsync("/api/values");
        }
    }
}

But this throws the following exception:

Test method TestRepro.Tests.UnitTest1.TestMethod1 threw exception: System.InvalidOperationException: Can't find'[path removed]\TestRepro.Tests\bin\Debug\TestRepro.deps.json'. This file is required for functional tests to run properly. There should be a copy of the file on your source project bin folder. If that is not the case, make sure that the property PreserveCompilationContext is set to true on your project file. E.g '<PreserveCompilationContext>true</PreserveCompilationContext>'. For functional tests to work they need to either run from the build output folder or the TestRepro.deps.json file from your application's output directory must be copied to the folder where the tests are running on. A common cause for this error is having shadow copying enabled when the tests run.

I have verified that TestRepro.deps.json exists in the web application output folder (TestRepro\bin\Debug\net47), but it is not copied to the test project output folder (TestRepro.Tests\bin\Debug). And I have not been able to find out how to disable shadow copying.

Edit: The documentation says:

The Microsoft.AspNetCore.Mvc.Testing package handles the following tasks: Copies the dependencies file (*.deps) from the SUT into the test project's bin folder.

But that doesn't seem to work. I can copy the file manually, but that doesn't work in an automated build scenario. One way would be to have a build step doing it in TeamCity, but it feels crude. Any ideas?

I have a repro on GitHub if that helps.

11 Answers 11

128

We should get "Program" class from the main project but it automatically references Microsoft.AspNetCore.Mvc.Testing.Program class

public class VersioningTests : IClassFixture<WebApplicationFactory<Program>>

this code must reference our main Program code. So we must put a reference to the Program class on the last line in Program.cs file:

public partial class Program { }
Sign up to request clarification or add additional context in comments.

5 Comments

There is an example project in Github by Damian Edward about Integration/Unit Tests in .NET 6 with minimal API and he makes the Program class public. Reference her github.com/DamianEdwards/MinimalApiPlayground/blob/main/src/…
Better variant: add visibility to internal Program for test project with [assembly: InternalsVisibleTo("IntegrationTests")] , and Program don't make public,
I needed to unload and reload my Testproject and then restart Visual Studio before it started using the correct Program reference.
@Ahmet Arslan I want to thank you! This was helpful.
I think adding "public partial class Program { }" at the end after the app.Run() line worked for me. Now I get an error in my test on a Times.Once() statement, but at least I think it is working now. Thank you.
46

I just ran into this same issue and found the root cause to be quite obscure. From the documentation, the .deps files should be copied to the integration test project's bin directory. This wasn't happening for me because was not explicitly referencing the Microsoft.AspNetCore.Mvc.Testing package from my integration test project. I had created a shared library with some utility functions that referenced that nuget package, so my integration test project indirectly referenced it.

There's some custom build tasks in the Microsoft.AspNetCore.Mvc.Testing package that copy the referenced service deps.json files for you, so you must reference it directly from the integration test project in order to get those build tasks to run.

2 Comments

If you run into the same problem as listed above and using .net core, the solution described in this answer is extactly what you need. I had forgotten this aswell in my integration test project.. Thanks alot for your answer @TylerOhlsen.
This was the solution for me too. Tests were working until I'd created a shared library and refactored out duplicate dependencies. The unit tests project must reference Microsoft.AspNetCore.Mvc.Test for the voodoo with deps.json to take place.
46

Okay, after almost two hours of trying to solve this... I got it.

My issue was I was using the new .NET6 Minimal APIs Program.cs format which does not have Program class (nor a namespace) defined and I was literally referencing the wrong class in the WebApplicationFactory<Program> definition... it came from Microsoft.VisualStudio.TestPlatform.TestHost (seriously WTF), so what you need to do is:

  1. Use your own actual Program.cs, so you add a namespace to your Minimal APIs Program.cs file and create an actual Program class with a Main method.
  2. Now you can reference the proper Program class as the generic type for the WebApplicationFactory
  3. Make sure you make internals visible in the web app project so you can expose the Program class (if you marked it internal).

This is basically an additon to Ahmets answer here: https://stackoverflow.com/a/70490057/1534753

6 Comments

Upvote for visibility, this was my case also
This was my problem as well.. I'm seriously considering turning off automatically adding using statements. Thanks!
Up vote, this is literally what just happened to me
my case as well
This helped me understand the answer by @Ahmet Arslan above. I just put the following line at the end of Program.cs public partial class Program { }
|
17

Follow steps below to create Integration Test for Asp.Net Core with targeting net 47.

  1. Create New Project-> xUnit Test Project(.Net Core)
  2. Right click new project->Edit .csproj->Change TargetFramework to net47
  3. Add Project Reference to TestRepro
  4. Install-Package Microsoft.AspNetCore.Mvc.Testing
  5. Add Test file like below

    public class BasicTests
    : IClassFixture<WebApplicationFactory<Startup>>
    {
        private readonly WebApplicationFactory<Startup> _factory;
    
        public BasicTests(WebApplicationFactory<Startup> factory)
        {
            _factory = factory;
        }
    
        [Fact]
        public async Task TestMethod1()
        {
            var client = _factory.CreateClient();
            var response = await client.GetAsync("/api/values");
        }
    
    }
    
  6. Run Test Project

7 Comments

Yes, that actually works! But I don't understand why. Is it because it started out as a .NET Core project and then was re-targeted? Or is it becuase it is using xUnit rather than MSTest framework?
@HenrikOlsson I assume it is related with MSTest. For the doc, it is used with xunit test.
No it's not - I just tried creating a MSTest project the same way, as in your answer, and that worked as well. So my conclusion is that you have to begin with target .Net Core and then change target.
This didnt fix my issue when I want to target .net core. What should I do?
@SamuelJ does my answer fix your issue?
|
6

For those trying to do Integration testing from unit testing on a minimal API setup (e.g.):

[TestMethod]
public void Test()
{
    var application = new WebApplicationFactory<Program>().WithWebHostBuilder(builder =>{});
    var body = JsonSerializer.Serialize(request);
    var content = new StringContent(body, Encoding.UTF8, "application/json");
    var client = application.CreateClient();

    var response = client.PostAsync("myendpoint", content).Result;
}

You can expose the application Program (class) to the unit testing adding a Program partial class as follow(e.g. Program.UnitTests.cs):

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("UnitTests")]

namespace API;

partial class Program {}

It took me a while to get a right solution for the minimal API setup, so I hope this avoid others to waste much time looking for a solution as I did. I obtained this from the following source (in case you need more information): How to test minimal APIs in ASP.NET Core 6

1 Comment

This answer goes well with the other by @Vedran Mandić. Between the two I was able to figure it out.
6

I've had the same error message.

Try to add the project reference to the SUT project (the project that I want to test).

Project Referance in the solution explorer

1 Comment

Great answer, considering now days a lot of devs are using new concepts, separated layers, decoupled projects, when you build the test project for the API, it is common that you don't have to import anything from de API by itself, so we forget about this reference.
5

For me, I already had a reference to Microsoft.AspNetCore.Mvc.Test in my test project, but removing the following fixed the issue:

<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

1 Comment

This essentially fixed it for me when upgrading to .NET 5.0, which is strange. But I have a shared assembly info so I removed that line and replaced it with: <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute> <GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute> <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
1

Accepted answer assumes that deps.json file exists in your project bin folder, so it can be copied into integration test bin folder.
In my case deps.json file was missing in application bin folder. In this case make sure you have

<PreserveCompilationContext>true</PreserveCompilationContext>

in your csproj file.

Comments

0

I'm facing the same issue and I want to share with you a way to make it copy to publish below:

Find the .csprj test file Add the following code would help you get through.

p/s I'm using .net core 3.1, so it would be useful for .net core test prj.

   <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <IsPackable>false</IsPackable>
      </PropertyGroup>
     <Target Name="CopyDepsJsonFiles" AfterTargets="Publish">
            <ItemGroup>
              <DepsJsonFiles Include="$(TargetDir)*.deps.json" />
            </ItemGroup>
            <Copy SourceFiles="@(DepsJsonFiles)" DestinationFolder="$(PublishDir)" />
        </Target>
<!-- ... other elements-->
    </Project>

Comments

0

My app's target framework is net8.0-windows and it uses minimal API. Adding this to the main app project file resolved the exception described by the OP:

  <ItemGroup>
    <InternalsVisibleTo Include="ScaAutomation.IntegrationTests" />
  </ItemGroup>

Comments

0

I fixed the testhost.deps.json not found error when using WebApplicationFactory by trying three solutions in order. This error typically happens because the test runner can't find the dependency information for your API project.

Here are 3 potential fixes, from simplest to most robust.
I was using NUnit with .NET 8 when I ran into this kind of issue.

Solution 1: The .csproj Quick Fix

This is the most common and least invasive solution. Edit your API project's .csproj file and add the <PreserveCompilationContext>true</PreserveCompilationContext> property. This tells the build process to output the dependency files that WebApplicationFactory are needed.

File: YourApiProject.csproj

<PropertyGroup>
  <TargetFramework>net8.0</TargetFramework>
  
  <!-- Add this line -->
  <PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>

While you're there, also ensure your test project can see the API's Program class by adding InternalsVisibleTo.

<ItemGroup>
  <InternalsVisibleTo Include="YourIntegrationTestProject" />
</ItemGroup>

For many, this is all that's needed. If it still fails, move to Solution 2.

Solution 2: Make the Program Class Explicitly Public

If you're using Minimal APIs, the auto-generated Program class is internal. This can cause visibility issues. You can fix this by adding a single line to the end of your Program.cs file to make the class public.

File: Program.cs

var builder = WebApplication.CreateBuilder(args);
// ... all your setup code
var app = builder.Build();
// ... all your pipeline code
app.Run();

// Add this line at the end of the file
public partial class Program { }

This merges with the auto-generated class, making it public and visible to your test project. This resolves visibility issues without changing build settings.

Solution 3: Full Control with an Explicit Main Method

This is the most robust solution as it completely removes any ambiguity about your application's entry point. Refactor your Program.cs to use a traditional structure with a declared namespace and a Main method.

File: Program.cs

// 1. Declare a namespace
namespace YourApiProject.Api;

public class Program
{
    // 2. Move all your startup code into a Main method
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        // ... your service configuration
        var app = builder.Build();
        // ... your middleware pipeline
        app.Run();
    }
}

Then, in your test project, update WebApplicationFactory to use the new, fully-qualified name.

File: WebAppFactory.cs

// Use the unambiguous, fully-qualified name
public class WebAppFactory : WebApplicationFactory<YourApiProject.Api.Program>
{
    // ...
}

This approach worked for me when the others didn't, as it leaves no room for confusion about which Program class to load.

New contributor
Deullam Justi is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.