Do you put unit tests in the same project for convenience or do you put them in a separate assembly?
If you put them in a separate assembly like we do, we end up wit
Put Unit tests in the same project as the code to achieve better encapsulation.
You can easily test internal methods, which means you wont make methods public that should have been internal.
Also it's really nice to have the unit tests close to the code you're writing. When you write a method you can easily find the corresponding unit tests because it's in the same project. When you build a assembly that includes unitTests, any errors in the unitTest will give you an compilereerror, so you must keep your unittest up-to-date, just to build. Having unittest in a seperate project, might cause some developers to forget building the unittest-project, and missing the broken tests for a while.
And you can remove the unit tests from the production code, by using compilation tags (IF #Debug).
Automatic Integration Tests (made i NUnit) should be in a seperate project since they don't belong to any single project.
I have recently been deploying in docker. I don't see the value in having a separate project when the Dockerfile can easily copy the /src directory and leave the /test directory. But I am new to dotnet and might be missing something.
In my opinion, unit tests should be placed in a separate assembly from production code. Here are just a few cons of placing unit tests in the same assembly or assemblies as production code are:
I don't really know of any pros. Having an extra project (or 10) isn't a con.
Edit: More Info On Build and Shipping
I would further recommend that any automated build process place production and unit tests into different locations. Ideally, the unit test build process only runs if the production code builds, and copies the product files into the unit tests directory. Doing it this way results in the actual bits being separated for shipping, etc. Additionally, it is fairly trivial to run automated unit testing at this point on all tests in a particular directory.
To summarize, here is the general idea for a daily build and testing and shipping of bits and other files:
Separate project, but in the same solution. (I've worked on products with separate solutions for test and production code - it's horrible. You're always switching between the two.)
The reasons for separate projects are as stated by others. Note that if you're using data-driven tests, you might end up with quite a significant amount of bloat if you include the tests in the production assembly.
If you need access to the internal members of the production code, use InternalsVisibleTo.
After spending some time in TypeScript projects, where tests are often placed in a file alongside the code they are testing, I grew to prefer this approach over keeping them separate:
So when I started a new .NET Core project recently I wanted to see if it was possible to mimic this structure in a C# project without shipping the tests or test assemblies with the final release.
Putting the following lines in the project file appears to be working well so far:
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<Compile Remove="**\*.Tests.cs" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' != 'Release'">
<PackageReference Include="nunit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
</ItemGroup>
The above ensures that in the Release
configuration all the files named *.Tests.cs
are excluded from compilation, and also that the required unit testing package references are removed.
If you still want to be able to unit test the classes in their release configuration you can just create a new configuration derived from Release
called something like ReleaseContainingTests
.
Update: After using this technique for a while I've also found it's helpful to customize your icons in VS Code to make the tests (and other things) stand out a bit more in the explorer pane:
To do this, use the Material Icon Theme extension and add something like the following to your VS Code preferences JSON:
"material-icon-theme.files.associations": {
"*.Tests.cs": "test-jsx",
"*.Mocks.cs": "merlin",
"*.Interface.cs": "yaml",
}
I put them in separate projects. The name of the assembly mirrors that of the namespaces, as a general rule for us. So if there is a project called Company.Product.Feature.sln, it has an output (assembly name) of Company.Product.Feature.dll. The test project is Company.Product.Feature.Tests.sln, yielding Company.Product.Feature.Tests.dll.
You are best keeping them in a single solution and controlling the output via the Configuration Manager. We have a named configuration for each of the main branches (Development, Integration, Production) in lieu of using the default Debug and Release. Once you have your configurations setup, you can then include or exclude them by clicking on the "Build" checkbox in the Configuration Manager. (To get the Configuration Manager, right-click the solution and go to Configuration Manager.) Note, that I find the CM in Visual Studio to be buggy at times. A couple of times, I have had to go into the project and/or solution files to clean up the targets that it created.
Additionally, if you are using Team Build (and I am sure that other .NET build tools are the same) you can then associate the build with a named configuration. This means that if you don't build your unit tests for your "Production" build, for example, the build project can be aware of this setting as well and not build them since they were marked as such.
Also, we used to do XCopy drops off of the build machine. The script would just omit copying anything named *.Tests.Dll from being deployed. It was simple, but worked.