views:

1640

answers:

13

How do you usually go about separating your codebase and associated unit tests? I know people who create a separate project for unit tests, which I personally find confusing and difficult to maintain. On the other hand, if you mix up code and its tests in a single project, you end up with binaries related to your unit test framework (be it NUnit, MbUnit or whatever else) and your own binaries side by side.

This is fine for debugging, but once I build a release version, I really do not want my code to reference the unit testing framework any more.

One solution I found is to enclose all your unit tests within #if DEBUG -- #endif directives: when no code references an unit testing assembly, the compiler is clever enough to omit the reference in the compiled code.

Are there any other (possibly more comfortable) options to achieve a similar goal?

+31  A: 

I definitely advocate separating your tests out to a separate project. It's the only way to go in my opinion.

Yes, as Gary says, it also forces you to test behavior through public methods rather than playing about with the innards of your classes

Galwegian
It also forces you to test behaviour through public methods rather than playing about with the innards of your classes. Double bonus imo.
Garry Shutler
I'd recommend a Different folder structure too. ProjName\Code\SubPackage and ProjName\Tests\SubPackage.
Gishu
What if you need to whitebox-test?
Roman Plášil
+1  A: 

I've always keep my unit tests in a seperate project so it compiles to it's own assembly.

Chris Canal
+2  A: 

For each project there is a corresponding .Test project that contains tests on it.

E.g. for the assembly called, say "Acme.BillingSystem.Utils", there would be a test assembly called "Acme.BillingSystem.Utils.Test".

Exclude it from the shipping version of your product by not shipping that dll.

Anthony
+3  A: 

I would recommend a separate project for unit tests (and yet more projects for integration tests, functional tests etc.). I have tried mixing code and tests in the same project and found it much less maintainable than separating them into separate projects.

Maintaining parallel namespaces and using a sensible naming convention for tests (eg. MyClass and MyClassTest) will help you keeping the codebase maintainable.

Rasmus Faber
+10  A: 

The .Net framework after v2 has a useful feature where you can mark an assembly with the InternalsVisibleTo attribute that allows the assembly to be accessed by another.
A sort of assembly tunnelling feature.

Rik Garner
+11  A: 

As the others point out, a seperate test project (for each normal project) is a good way to do it. I usually mirror the namespaces and create a test class for each normal class with 'test' appended to the name. This is supported directly in the IDE if you have Visual Studio Team System which can automatically generate test classes and methods in another project.

One thing to remember if you want to test classes and methods with the 'internal' accessor is to add the following line to the AssemblyInfo.cs file for each project to be tested:

[assembly: InternalsVisibleTo("UnitTestProjectName")]
Morten Christiansen
Thanks, this is a neat thing I was not aware of.
petr k.
Thanks also! This means we can stop making things public for the sake of the tests hurray! :D
Sam Wessel
If you strong-name your assemblies (as you should), then you need to add the public key long-string to the declaration too. Note: Strong-naming isn't a protection against third-party linkage to internals, since they can still be accessed via reflection.
Steve Gilham
A: 

I definitely agree with everyone else that you should separate the tests from your production code. If you insist on not, however, you should define a conditional comiplation constant called TEST, and wrap all of your unit test classes with a

#if TEST
#endif

first to ensure that the test code does not compile in a production scenario. Once that is done, you should either be able to exclude the test dlls from your production deployment, or even better (but higher maintenance), create an NAnt or MSBuild for production that compiles without the references to the test dlls.

Michael Meadows
+1  A: 

As long as your tests are in a seperate project, the tests can reference the codebase, but the codebase never has to reference the tests. I have to ask, what's confusing about maintaining two projects? You can keep them in the same solution for organization.

The complicated part, of course, is when the business has 55 projects in the solution and 60% of them are tests. Count yourself lucky.

tsilb
A: 

I always create a separate Acme.Stuff.Test project that is compiled separately.

The converse argument is: Why do you want to take the tests out? Why not deliver the test? If you deliver the tests along with a test runner you have some level of acceptance test and self test delivered with the product.

I've heard this argument a few times and thought about it but I personally still keep tests in a separate project.

Hamish Smith
+2  A: 

I put the tests in a separate project but in the same solution. Granted, in big solutions there might be a lot of projects but the solution explorer is good enough on separating them and if you give everything reasonable names I don't really think it's an issue.

Niklas Winde
+1  A: 

Yet another alternative to using compiler directives within a file or creating a separate project is merely to create additional .cs files in your project.

With some magic in the project file itself, you can dictate that:

  1. nunit.framework DLLs are only referenced in a debug build, and
  2. your test files are only included in debug builds

Example .csproj excerpt:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">

   ...

   <Reference Include="nunit.framework" Condition=" '$(Configuration)'=='Debug' ">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\..\debug\nunit.framework.dll</HintPath>
   </Reference>

   ...

   <Compile Include="Test\ClassTest.cs" Condition=" '$(Configuration)'=='Debug' " />

   ...
</Project>
+1  A: 

One thing yet to be considered is versions of VisualStudio prior to 2005 did not allow EXE assembly projects to be referenced from other projects. So if you are working on a legacy project in VS.NET your options would be:

  • Put unit tests in the same project and use conditional compilation to exclude them from release builds.
  • Move everything to dll assemblies so your exe is just an entry point.
  • Circumvent the IDE by hacking the project file in a text editor.

Of the three conditional compilation is the least error prone.

codeelegance
A: 

If the #if(DEBUG) tag allows for a clean "release" version, why would you need a separate project for tests. The nunit LibarryA/B example (yeah, I know its a example) does this. Currently wrestling with the scenario. Had been using a separate project, but this seems to possibly allow for some productivity improvements. Still hummin and hawin.

mbowles