Search code examples
c#unit-testingtesting.net-6.0toplevel-statement

Is there a way to unit test top-level statements in C#?


I was fiddling with top-level statements as the entry point for a simple console app, since the new .NET 6 template use them as a default.

Yet, as the language specification very clearly states:

Note that the names "Program" and "Main" are used only for illustrations purposes, actual names used by compiler are implementation dependent and neither the type, nor the method can be referenced by name from source code.

So, if I can't reference the implicit Program class and it's Main() method, would it be possible to write unit tests to check the execution flow of the top-level statements themselves? If so, how?


Solution

  • Yes. One option (since .NET 6) is to make the tested project's internals visible to the test project for example by adding next property to csproj:

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

    And then the Program class generated for top-level statement should be visible to the test project and you can run it next way:

    var entryPoint = typeof(Program).Assembly.EntryPoint!;
    entryPoint.Invoke(null, new object[] { Array.Empty<string>() }); 
    

    Something like this is used internally to perform integration tests for ASP.NET Core 6 with minimal hosting model.

    Note that generated Main method can return task if you are using await's in your top-level statement, so you possibly will need to capture the return of entryPoint.Invoke and test if it is a Task and await it.

    Another approach is to explicitly declare Program class as partial (for example at the end of top-level statement and use it in testing project):

    // ...
    // your top-level statements
    
    public partial class Program { }