5

I want to use WebApplicationFactory to create hosts for my tests, but I want to create 2 Web Application Factories for two projects I refereed in single XUnit test project.

When I refer only one project then everything is working fine.

But when I refer two projects, it seems that WebApplicationFactory cant recognize which Program class I want to use.

My goal is to have 2 classes for 2 dummy apps (like on the screen) in a single XUnit test project.

It seems that I cant precise which Program class I want to use in WebApplicationFactory with using statement.

Is it possible to create 2 Web Application Factories for different Pragram classes in one XUnit project, and if yes, then how to do this?

SOLVED THIS MYSELF - it seems that XUnit does not recognize that Program class in .NET6 is in a file where there is no namespace declaration. The solution is to create separate file with namespace declaration and 'public partial class Program{ }' inside. Then you are able to use full path in WebApplicationFactory<TestedProjectNamespace.Program>

How I`d like it to look

6
  • There shouldn't be an issue in doing this. If it's just struggling in recognising which Program class to use, why not put it's full path including namespaces etc? Commented May 1, 2022 at 17:59
  • I tried this, WebApplicationFactory<ProjectNamespace.Program> gives compilation error 'cannot resolve symbol'. It seems like it cannot find this class. Commented May 1, 2022 at 18:33
  • If you're using .net 6, you can modify the csproj file where your program file is and add the "InternalsVisibleTo" property. This is also Microsoft's recommendation as found here; learn.microsoft.com/en-us/aspnet/core/test/… That's probably the reason that XUnit can't find it Commented May 1, 2022 at 20:38
  • @scottdavidwalker Hi, thanks, I did it, the reason was different, I`ve edited my question and added solution for future reference Commented May 1, 2022 at 20:54
  • @jwtk can you please provide code snippet of your solution? Commented Nov 1, 2023 at 21:59

1 Answer 1

1

Fortunately, xUnit and the WebApplicationFactory class don't need to directly reference the global namespace, top level statement Program.cs Program class. We can often use any class from the project being tested that is sufficiently exposed to the test project. The type param description of TEntryPoint in WebApplicationFactory<TEntryPoint> states "A type in the entry point assembly of the application. Typically the Startup or Program classes can be used."

If you look at the source code for the WebApplicationFactory class, you will see that it uses reflection to find the app entry point. There are lots of references in the WebApplicationFactory class code to typeof(TEntryPoint).Assembly. It's basically saying "I just need a class type that belongs to an assembly with an entry point." It could be a page model, middleware, MVC controller, or just a dummy class. Doesn't need to be partial. A public class is usable in more scenarios than an internal class though, if you have trouble with internal.

Assuming all these classes are in the project being tested, we can just as well reference the project via possible code options like these:

MyTests : IClassFixture<WebApplicationFactory<WebProjectNamespace.MyMiddlewareClass>>

MyTests : IClassFixture<WebApplicationFactory<WebProjectNamespace.MyPageModelClass>>

MyTests : IClassFixture<WebApplicationFactory<WebProjectNamespace.MyHelloWorldController>>

Referencing the project's Program class is a better indicator that you're referencing the project startup than referencing a random controller or page class name, but it's not strictly necessary.

Another solution is to use Project/Assembly aliases to differentiate the two, like so:

In your test project csproj file:

<ProjectReference Include="..\WebProject1\WebProject1.csproj" Aliases="global,WebProject1Assembly" />
<ProjectReference Include="..\WebProject2\WebProject2.csproj" Aliases="global,WebProject2Assembly" />

In your test CS file:

extern alias WebProject1Assembly;
extern alias WebProject2Assembly;

...

MyTests1 : IClassFixture<WebApplicationFactory<WebProject1Assembly::Program>>

...

MyTests2 : IClassFixture<WebApplicationFactory<WebProject2Assembly::Program>>

Note that referencing Program often necessitates that Program be public in order to avoid "Inconsistent accessibility" errors. If you are using a top level statements file in the project being tested, you can make Program public by adding this at the bottom of the file:

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

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.