Removing test dependencies from .NET's release

There are a multitude of ways on how one can structure a .NET project. It’s no wonder one can also have a multitude of downsides when chosing one of them. At my $CURRENT_JOB we introduced Fable to our project and guess what? We had problems with our testing infrastructure that required some tweaking to make it happen (I’ll not get into the problem details here 😜).

After some trial and error I got the conclusion that our solution would get the most out of it if we just had a src and a tests directory inside each project. You can picture its structure like this:

./Solution.sln
./src/API/src/*.fs
./src/API/tests/*.fs
...

However, while this solved most of our previous issues, it also introduced two new problems:

  1. test code would ship with our release binary
  2. we have multiple EntryPoints on our solution, how will this work out?

Removing unwanted code from our releases

I assumed that .NET would remove code with “Test” attributes and unused code from the release artifact. Oh boy, was I wrong. This is a bummer because you don’t want to ship more information than is needed as one might be able to strip debug symbols or even decompile a bunch of code you may not want others to see.

After some research, I found this Stack Overflow answer showing a way of disabling this code during release. They even introduced a new way of structuring tests, how nice! This is how my .fsproj file looked as after some testing:

<!-- Project-related group -->
<ItemGroup>
    <!-- Project files -->
    <Compile Include="src/Program.fs" />

    <!-- Project-related dependencies -->
    <PackageReference Include="FsToolkit.ErrorHandling" Version="4.4.0" />
</ItemGroup>

<!-- Test-related group -->
<ItemGroup Condition="'$(Configuration)' != 'Release'">
    <!-- Test files -->
    <Compile Include="tests/Shared.fs" />

    <!-- Test dependencies -->
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*"/>
</ItemGroup>

Now, the only important part here is the attribute Condition="'$(Configuration)' != 'Release'". Basically it’s saying that this ItemGroup should only be evaluated if we are not releasing. You don’t need to organize your project file like I did but, personally, I liked how it looked.

Dealing with EntryPoints

You can see that I left the test dependency Microsoft.NET.Test.Sdk. It was on purpose, this almost made me have a mental breakdown! I kept getting the following error:

error FS0433: A function labeled with the 'EntryPointAttribute' attribute must be the last declaration in the last file in the compilation sequence.

No matter how much I messed with the project file, OutputTypes and EntryPoints, I couldn’t get this error1 to go away! At this point, removing as much code as possible from the error context helped a lot. Such as that I discovered the problem when I had this single dependency left!

Again, someone may have faced the same issue, right? Yes, someone have! The fix is really simple, just add this attribute on your project file:

<GenerateProgramFile>false</GenerateProgramFile>

  1. Being honest here, I’m glad I have setup my project to error on build warnings↩︎


Articles from blogs I follow around the net

The four tenets of SOA revisited

Twenty years after. In the January 2004 issue of MSDN Magazine you can find an article by Don Box titled A Guide to Developing and Running Connected Systems with Indigo. Buried within the (now dated) discussion of the technology…

via ploeh blog March 4, 2024

Building a demo of the Bleichenbacher RSA attack in Rust

Recently while reading Real-World Cryptography, I got nerd sniped1 by the mention of Bleichenbacher's attack on RSA. This is cool, how does it work? I had to understand, and to understand something, I usually have to build it. Well, friends, that is what…

via ntietz.com blog March 4, 2024

How to unbreak Dolphin on SteamOS after the QT6 update

A recent update to Dolphin made it switch to QT6. This makes it crash with this error or something like it: dolphin-emu: symbol lookup error: dolphin-emu: undefined symbol: _Zls6QDebugRK11QDockWidget, version Qt_6 This is fix…

via Xe Iaso's blog March 3, 2024

Generated by openring