170

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 with a number of extra projects in the solution. It's great for unit testing while coding but how do you release the application without all of these extra assemblies?

multitask landscape
  • 8,273
  • 3
  • 33
  • 31
leora
  • 188,729
  • 360
  • 878
  • 1,366

16 Answers16

136

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    +1: I've just encountered unit tests in the same project as the main code and it is hard to find the tests amongst the real code - even though a naming convention has been followed. – Fenton Sep 13 '12 at 10:43
  • 46
    For less experienced reader this means you add `[assembly:InternalsVisibleTo("UnitTestProjectName")]` to your project `AssemblyInfo.cs` file. – Margus Jun 18 '14 at 07:13
  • Very useful addition Margus. Thanks to Jon for mentioning InternalsVisibleTo in this context. – Bjørn Otto Vasbotten Aug 27 '14 at 08:21
  • Be careful with `InternalsVisibleTo` - you should be signing your assemblies and only allowing specific signatures to see the internals. If not, you are opening the door to malicious code. For example, someone could masquerade as `UnitTestProject` just to be able to call into your assembly during runtime and wreak all sorts of havoc. Depending on what project it is, this could be *very bad*. See [this page](https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute(v=vs.110).aspx) – jropella Sep 30 '15 at 21:42
  • 1
    @jropella: If you're signing the prod assembly, you can only make the internals visible to signed assemblies anyway. And of course if you're running any code in full trust, they have access via reflection... – Jon Skeet Sep 30 '15 at 21:44
  • @JonSkeet: Yes, this is precisely my point. I've observed unsigned assemblies with `InternalsVisibleTo`, so the reflection would have been possible by any assembly with the given name (afaik). – jropella Nov 12 '15 at 03:02
  • 2
    @jropella: Reflection doesn't care about InternalsVisibleTo anyway... but you wouldn't have seen a *signed* assembly trusting an *unsigned* assembly using InternalsVisibleTo, because that's prevented at compile-time. – Jon Skeet Nov 12 '15 at 06:55
  • @jropella: Is there any reason not to exclude `InternalsVisibleTo` for the production version with an `#if`? I mean, other than the maxim that you should always test unaltered code - but if the production assembly is signed as opposed to the one you tested with, we are not strictly following that maxim any more, and if the C# compiler works correctly, the one particular additional assembly attribute should not make any difference in runtime behaviour. – O. R. Mapper Nov 11 '16 at 10:20
  • @O.R.Mapper That would suggest you're happy never running tests against the binary you ship. – Jon Skeet Nov 11 '16 at 10:22
  • @JonSkeet: That's indeed a concern; I (probably erroneously) read "If you're signing the prod assembly" to possibly imply that the test assembly is not signed, as opposed to the production-state actual application assembly. – O. R. Mapper Nov 11 '16 at 10:24
  • @jropella: It appears that Microsoft now [recommends _against_](https://github.com/dotnet/runtime/blob/master/docs/project/strong-name-signing.md) strong-name signing of assemblies. _"For the most part, the majority of applications do not need strong-names. Strong-names are left over from previous eras of .NET..."_ Given this current guidance, is there still a security risk using `InternalsVisibleTo` with unsigned assemblies? – mwolfe02 Sep 14 '20 at 04:34
117

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:

  1. Unit tests get shipped with production code. The only thing shipped with product code is production code.
  2. Assemblies will be unnecessarily bloated by unit tests.
  3. Unit tests can affect build processes like automated or continuous build.

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:

  1. Production build runs, placing production files into a specific "production" directory.
    1. Build production projects only.
    2. Copy compiled bits and other files into a "production" directory.
    3. Copy bits and other files into a release candidate directory, aka a Christmas release directory would be "Release20081225".
  2. If production build succeeds, unit test build runs.
    1. Copy production code to "tests" directory.
    2. Build unit tests to "tests" directory.
    3. Run unit tests.
  3. Send build notifications and unit tests results to developers.
  4. When a release candidate (like Release20081225) is accepted, ship these bits.
Jason Jackson
  • 17,016
  • 8
  • 49
  • 74
  • 25
    IMO the cons you list aren't always applicable. A pro for same-project is easier grouping of tested class + tests - these small conveniences go a long way when writing tests. Personal preference wins here, and sometimes your points are relevant, just not all the time. – orip Dec 07 '08 at 09:06
  • but how do you remove these projects when you want to ship – leora Dec 07 '08 at 11:47
  • 9
    You should first ask whether you need to remove the tests when you ship. If yes, you need a separate project. If not, use the other pros and cons to decide. People that assume they can't deploy the tests will always reach the "separate project" conclusion by default. – orip Mar 17 '10 at 16:28
  • 10
    I don't see any upsides to shipping non-production code like unit tests, and there are plenty of downsides. Shipping unit tests means you are dealing with more bits that need to be distributed. Unit tests also have a separate set of dependencies. Now you are shipping NUnit, Rhino or Moq, etc. That is even more bit bloat. Placing unit tests into a separate project requires only a small amount of effort, and that is a one time cost. I am very comfortable with the conclusion that unit tests shouldn't be shipped. – Jason Jackson Mar 18 '10 at 23:22
  • @JasonJackson you only need the extra dependencies at build time, you don't need to distribute the dependencies in production code. Having the tests on the same assembly allows you to have always tests and code in sync, you won't be executing tests against outdated code. – Ignacio Soler Garcia Sep 06 '12 at 08:39
  • @SoMoS I have never seen this done. Any good CI is going to check out all the code including test code at the same time, build, then execute tests. You are addressing a problem that doesn't exist as long as the code is all in the same repo. – Jason Jackson Sep 20 '12 at 19:48
  • @JasonJackson: where I work all the test infrastructure is built separately from the main build to avoid having a build break by a test (build its a long process), so I faced this problem several times. That's why I thought it sounds like a good idea to have it all together. – Ignacio Soler Garcia Sep 21 '12 at 08:56
  • @SoMoS I still don't understand why you cannot separate it into separate projects in the same solution as the main build. – Jason Jackson Sep 21 '12 at 22:24
  • @JasonJackson: if they are on the main build and something breaks the tests the you don't have build. Where I work the main build is considered critical while the tests are not so important. That's why the tests are not on the same solution as the build. (We're talking about a solution with 200+ projects) – Ignacio Soler Garcia Sep 24 '12 at 09:27
  • 3
    One very big con for placing the tests in different projects: The tests are far away, there is lots of clicking before reaching the UnitTest code. This increases the chance of UnitTests not being done/updated. IMO that outweighs the 3 cons listed above. – Laoujin Jul 02 '13 at 09:01
  • @Laoujin: The proximity of tests is a valid point. In addition to issue related to test accessibility or barriers to updating, it makes sense to keep related code in one place. Since the logic being tested is encapsulated in the target class there is some value in having test and test subject right next to each other. How much that is worth will vary between developers though. – Rich C Feb 07 '14 at 03:25
  • 7
    As an alternative to the "separate project" approach for removing unit tests in production code, consider using a custom symbol and compiler directives like `#if`. This custom symbol can be toggled using compiler command-line parameters in your CI software scripts. See http://msdn.microsoft.com/en-us/library/4y6tbswk.aspx. – Rich C Feb 07 '14 at 03:35
  • In Java one would typically put test code in the same module/project as the production code. The test code lives in the `testsrc` folder, and production code in the `src` folder. This is hard (?) to achieve in Visual Studio since source code is placed in the root folder of the project - really weird!! I can understand then why a separate test project seems logical even though it doubles the number of projects in a solution making it harder to get an overview. – Arne Evertsson Nov 07 '14 at 13:55
  • 36
    .NET is behind the curve on having tests in a completely separate project, and I would bet that this will change, soon. There's no reason the build process could not be made to ignore test code in the release build. I have used several web app generators that do this. I think it is absolutely better to include unit test codefiles right alongside the codefiles they describe, peppered throughout the same file hierarchy. Google recommends this, called the 'fractal' file organization. Why are tests any different than inline comments and readme documentation? The compiler gladly ignores the latter. – Brandon Arnold Jan 28 '15 at 18:17
  • While I agree in principle with what is the core of the reply, I do agree too with many of the comments made that you have to make a list of pros and cons every time. – Isaac Llopis Feb 02 '16 at 11:06
  • 3
    I have downvoted the reply. Although the argument is solid enough, all the replies below point what should be a rule in StackOverflow: A reply starting with the words _"in my opinion"_ is not a good StackOverflow reply. A good reply would have been "The general norm in the .NET world would be..." or "You have to decide for your own situation, but..." – Isaac Llopis Apr 07 '16 at 13:37
  • 1
    A view from a different perspective: Rust handles this very well in my opinion. In rust you write unit tests (only unit test) in the same file as the implementation but put it inside a module (namespace) annotated with a Test Attribute. When you compile your crate (project) Rust will not compile your tests into the binary... – Noel Widmer Jun 30 '18 at 19:35
  • The advantage of this is that you can test private functions and your tests are in the same location as the implementation (Ever happended that your implementation directory structure changed and diverged from the test directory structure?). Having unit tests in the same location as the units they test is amazing. I don't see a negative impact in the way that Rust does it. I'd still not recommend doing this in C# because your code will be compiled into the output. – Noel Widmer Jun 30 '18 at 19:35
  • Sorry, but this answer is incomplete. You failed to mention any Pros. Also, there are different types of tests (unit, integration, e2e), and it might make sense to place each type somewhere else. The huge advantage I see if _unit_ tests are colocated with the implementation, is that it's much easier to reason about the implementation, and navigate between the tests and the implementation. If unit tests are placed in a separate project, it's a complete mess, especially if you have thousands of tests. .NET is serously behind in this regard. – Jan Kalfus Jul 19 '21 at 15:16
72

I do not understand the frequent objection to deploying tests with production code. I led a team at a small microcap (grew from 14 to 130 people). We had a half-dozen or so Java apps and we found it EXTREMELY valueable to deploy tests into the field to execute them on a specific machine that was exhibiting unusual behavior. Random problems occur in the field and being able to throw a few thousand unit tests at the mystery with zero cost was invaluable and often diagnosed problems in minutes...including installation problems, flaky RAM problems, machine-specific problems, flaky network problems, etc, etc. I think it is incredibly valuable to put tests into the field. Also, random problems pop up at random times and it is nice to have the unit tests sitting there already waiting to be executed at a moments notice. Hard-drive space is cheap. Just like we try to keep data and functions together (OO design), I think there is something fundamentally valuable in keeping code and tests together (function + tests that validate the functions).

I would like to put my tests in the same project in C#/.NET/Visual Studio 2008, but I still haven't investigated this enought to achieve it.

One big benefit of keeping Foo.cs in the same project as FooTest.cs is that developers are constantly reminded when a class is missing a sibling test! This encourages better test-driven coding practices...holes are more apparent.

  • 21
    I can see how the would be valuable with integration tests, but for unit tests? If you write them correctly they shouldn't have any dependencies on the machine. – Joel McBeth Apr 26 '12 at 18:51
  • +1 I agree. As i am doing mostly .NET, shipping testing with production code also has the nice side effect of reducing the continuous integration step of compile & test: 1) Only half projects to build, 2) all testing assemblies in the place of the main application so it is easier to parameterize your test runner. When using Maven this argument does not hold, of course. Finally, my customers are more technical folks and they really like to be able to run the tests themselves as this is documenting the current state against the spec. – mkoertgen Oct 04 '13 at 10:57
  • I think it can make perfect sense to do integration testing in TDD/BDD style, that is writing test code that can be easily automated with standard test runners like NUnit, xUnit etc. Of course, you should not mix up unit with integration testing. Just make sure you know which set of tests to run quickly & often for build verification (BVT) and which ones for integration testing. – mkoertgen Oct 04 '13 at 11:02
  • 1
    The reason people object to it is because that's not what they're used to. If their first experience unit testing was that they were within the production code, in fact, with specific syntax in the programming language that indicated what a test is associated with a production method, they would swear that that was an invaluable aspect of the development workflow and it's absolutely crazy to put them in a separate project. Most devs are like this. Followers. – zumalifeguard Dec 10 '14 at 00:57
  • You should not force test bits on your customers. Publishing unit test for your components is a best practice however, just don't include them with your production bits. Not everybody needs them and they can cause breakage, when your test infrastructure conflicts with mine. – jwdonahue Feb 02 '21 at 22:40
57

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:

  • It is quicker to navigate to the test file.
  • It is easier to remember to rename the tests when you rename the class being tested.
  • It is easier to remember to move the tests when you move the class being tested.
  • It is immediately obvious if a class is missing tests.
  • You don't need to manage two duplicate file structures, one for tests and one for code.

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:

VS Code Screenshot

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": "Raml",
}

Update 2:

If you get the error Program has more than one entry point defined then you can follow the instructions here, which is basically to add <GenerateProgramFile>false</GenerateProgramFile> inside a <PropertyGroup> element in your project's .csproj file, and this will stop the testing framework from adding its own entry point.

James Thurley
  • 2,650
  • 26
  • 38
  • 2
    Exactly what we've just started doing – Matthew Steeples May 28 '20 at 16:31
  • Have you got this working for .net standard class libraries as well? – Zenuka Jul 24 '20 at 11:31
  • How do you get around the 'Program has more than one entry point defined' error? – RoboKozo Feb 26 '21 at 16:13
  • 2
    @RoboKozo you can add `false` in your project file inside the `` tag. See here for more: https://andrewlock.net/fixing-the-error-program-has-more-than-one-entry-point-defined-for-console-apps-containing-xunit-tests/ – James Thurley Feb 26 '21 at 16:18
  • I love this idea and was thinking something simmilar. The problem that either you deploy your tests in the production binary or you cant test the production binary. In a CI environment, for example. You will always need two builds, one for testing and another for releasing the binary. Or will always publish your tests alongside with the features, increasing binary sizes and possibly memory consumption. – Andre Soares Mar 04 '21 at 02:53
  • After spent some time coding in golang, I fall in love with this approach. I think we can use ``` ``` to ensure that test code don't go to prod. – Jedi31 Apr 22 '21 at 23:32
  • 1
    Great, the trick with the icons did not take effect for me, but otherwise the approach (if that's what you want) works really well. I'd suggest adding the advice about `GenerateProgramFile` in the answer as well as it bit me. – Robert Cutajar Jul 16 '21 at 10:41
  • @Rbjz thanks for the suggestion, I've added that information to the answer. – James Thurley Aug 10 '21 at 12:10
  • Hi @JamesThurley, I liked your points very much, and I've been using a similar technique in a .NET Framework solution. However, when building a new solution having .NET Core applications and .NET standard class libraries in lower layers, I've realized that MS testing framework does not supports putting unit tests in assemblies targetting netstandard, but only in netcoreapp or net framework. While the technical reasoning is clear, it's still a huge pain after spending a few time with this. Have you faced the same issue? Do you probably have any suggestions or workarounds? Thanks in advance. – Zoltán Tamási Mar 04 '22 at 20:44
  • @ZoltánTamási I haven't had to face that issue yet, so I don't have any additional help to offer I'm afraid. Interested to know if you find a solution though. – James Thurley Mar 14 '22 at 16:20
  • 1
    @JamesThurley it turned out that it's a conceptual limitation, as targeting netstandard does not imply anything on target runtime. However, from net5.0 we can do this again. This aligns well with [@orip's answer](https://stackoverflow.com/a/347411/1323504), because in shared library code netstandard is still preferred for wider compatibility. So to summarize, from net5.0 on, I prefer using the same project in application projects, and separate project for shared library's targetting netstandard. – Zoltán Tamási Mar 16 '22 at 08:17
  • Works really well in general. Big fan of this concept – drewid Jul 04 '22 at 00:44
22

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.

Community
  • 1
  • 1
jenspo
  • 504
  • 4
  • 11
  • 1
    But that means you cannot run tests on the `Release` build and few "heisenbugs" can fall through. – hIpPy Jun 06 '13 at 16:37
  • 5
    With friend assemblies ( https://msdn.microsoft.com/en-us/library/0tke9fxk.aspx ) using `InternalsVisibleTo` allows you to test internal methods from a seperate test project – ParoX Mar 26 '16 at 18:47
  • 3
    @hlpPy - you can configure arbitrary conditional compilation symbols, and you can have more than 2 build configurations. E.g; you might have `Debug`, `Approval` and `Release`; and compile approval with all release optimizations. Also, typically unit tests aren't great at detecting heisenbugs in the first place (in my experience). You tend to need specific integration regression tests for those - and you may well place those side-by-side. – Eamon Nerbonne Sep 28 '16 at 13:43
  • A separate project gives the same compile time error. If you need to get that deep in the code then sounds more like you need more abstractions than hack unit tests into your code. Relying conditionals in your code to switch branches is not good either. Sounds more like Unit and Integrations tests are being confused. – Nick Turner Oct 28 '19 at 14:18
  • My main concern with shipping production + test code in an assembly, is that they tend to exponentially increase the attack surface. Online code is subject to many known/unknown vulnerabilities, why would anyone want to increase that surface area? You may not think your component is security critical, but you have no idea how security sensitive the systems are that employ your component. The bigger the pre-positioned tool kit on the server, the easier it is for an attacker to own it, and your test code could easily become the key vector in a successful attack. – jwdonahue Feb 02 '21 at 23:03
12

My unit tests always go in a separate project. In fact, for every project I have in my solution, there is a separate test project that goes along with it. Testing code is not application code and should not be intermingled with it. One advantage to keeping them in separate projects -- at least using TestDriven.Net -- is that I can right-click on a test project and run all the tests in that project, testing an entire library of application code with one click.

tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • 1
    Then how do you unit test internal classes? Or do you only test the public classes? – user19371 Dec 07 '08 at 03:57
  • 9
    if necessary, although I typically only test public interfaces. – tvanfosson Dec 07 '08 at 04:21
  • @tvanfosson, what do you do with Specs (Specflow)? Would you have a separate project or would you put them in the Unit Test project? +1. – w0051977 Mar 22 '18 at 17:03
  • @w0051977 I've never used Specflow so I don't know – tvanfosson Mar 22 '18 at 17:31
  • @tvanfosson, what about integration tests? Would you put them in a separate project to the unit tests? – w0051977 Mar 22 '18 at 17:35
  • @w0051977 yes, integration tests go in one or more separate projects. This makes it easier to exclude them from the automated tests run by the continuous integration server. They are frequently long running and we don't want the build held up. They ARE part of the release process, just not automated builds. – tvanfosson Mar 22 '18 at 17:56
  • @tvanfosson, what namespaces do you use for testing? Is it: MyCompany.MyProduct.MyFeature.Tests.Unit and MyCompany.MyProduct.MyFeature.Tests.Integration? – w0051977 Mar 26 '18 at 09:05
  • @w0051977 *.Tests and *.IntegrationTests - makes it easier to include only the *.Tests projects in test discoverability in the CI/CD pipeline – tvanfosson Mar 26 '18 at 13:20
11

If NUnit framework is used, there is an additional reason to put the tests in the same project. Consider the following example of the production code mixed with unit tests:

public static class Ext
{
     [TestCase(1.1, Result = 1)]
     [TestCase(0.9, Result = 1)]
     public static int ToRoundedInt(this double d)
     {
         return (int) Math.Round(d);
     }
}

The unit tests here serve as documentation and specification to the code being tested. I do not know how to achieve this effect of self-documenting, with the tests located in a separate project. The user of the function would have to search for the tests to see those test cases, which is unlikely.

Update: I know that such usage of TestCase attribute was not that the developers of NUnit intented, but why not?

Andrej Adamenko
  • 1,650
  • 15
  • 31
3

I fluctuate between same project and different projects.

If you're releasing a library releasing the test code with the production code is a problem, otherwise I find it usually isn't (although there's a strong psychological barrier before you try).

When putting tests in the same project I find it easier to switch between tests and the code they test, and easier to refactor/move them around.

orip
  • 73,323
  • 21
  • 116
  • 148
3

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.

Joseph Ferris
  • 12,576
  • 3
  • 46
  • 72
3

I know this is a very old question, but I would like to add my experience there I recently change unit testing habit from separate projects to same one.

Why?

First I am very tend to keep main project folder structure same with test project. So, if I have a file under Providers > DataProvider > SqlDataProvider.cs then I am creating same structure in my unit test projects like Providers > DataProvider > SqlDataProvider.Tests.cs

But after project is getting bigger and bigger, once you move files around from one folder to another, or from one project to another, then it is getting very cumbersome work to sync those up with unit test projects.

Second, it is not always very easy to navigate from class to be tested to unit test class. This is even harder for JavaScript and Python.

Recently, I started to practice that, every single file I created (for example SqlDataProvider.cs) I am creating another file with Test suffix, like SqlDataProvider.Tests.cs

At the beginning it seems it will bloat up files and library references, but at long term, you will eliminate moving file syndrome at first glance, and also you will make sure, every single file those are candidates of being tested will have a pair file with .Tests suffix. It gives you easy of jumping into test file (because it is side by side) instead of looking through separate project.

You can even write business rules to scan through project and identify class which does not have .Tests file, and report them to the owner. Also you can tell your test runner easily to target .Tests classes.

Especially for Js and Python you will not need to import your references from different path, you can simply use same path of target file being tested.

I am using this practice for a while, and I think it is very reasonable trade-off between project size vs maintainability and learning curve for new comers to the project.

Teoman shipahi
  • 47,454
  • 15
  • 134
  • 158
  • I disagree. It's much more organized to group items then testing individual classes. If your testing your providers; You would have an IProvider, ISqlProvider, and a MockSqlConnection. In a Provider folder you would have the Unit Test for each provider. You can go that deep on unit tests, but then your just writing tests and not code and may even remove the pro and starts writing code to test. – Nick Turner Oct 28 '19 at 14:24
1

I would say keep them separate.

On top of the other reasons mentioned, having code and tests together skews test coverage numbers. When you report on unit test coverage - reported coverage is higher because the tests are covered when you run unit tests. When you report on integration test coverage, the reported coverage is lower because integration tests would not run unit tests.

Sebastian K
  • 6,235
  • 1
  • 43
  • 67
  • Does that not depend on the technology used to cover the tests? I mean, OpenCover considers lines of code covered if they are run by a test, _including the lines of the test itself_ so that if tests have unexpected exceptions, they are flagged as uncovered too. – Isaac Llopis Apr 07 '16 at 13:33
0

I am really inspired by the unit testing framework of the Flood NN library by Robert Lopez. It uses a different project for every single unit tested class, and has one solution holding all these projects, as well as a main project that compiles and runs all the tests.

The neat thing is also the layout of the project. The source files are in a folder, but then the folder for the VS project is below. This allows you to make different subfolders for different compilers. All the VS projects are shipped with the code, so it is very easy for anyone to run any or all of the unit tests.

0

As others have answered - put tests in separate projects

One thing that hasn't been mentioned is the fact that you can't actually run nunit3-console.exe against anything but .dll files.

If you're planning on running your tests via TeamCity, this will pose a problem.

Let's say you have a console application project. When you compile, it returns an executable .exe to the bin folder.

From the nunit3-console.exe you wouldn't be able to run any tests defined in that console application.

In other words, a console application returns an exe file and a class library returns dll files.

I just got bit by this today and it sucks :(

Kellen Stuart
  • 7,775
  • 7
  • 59
  • 82
0

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.

MikeF
  • 764
  • 9
  • 26
0

Another disadvantage of shipping unit test code to production is that we are shipping the knowledge of how to actually use that code. This can be bad because the attacker will have an easier time understanding the business logic after successful decompilation of the unit tests. This can be really harmful. For example, your code could contain special logic to deal with the particularities of taxes between states and countries. This knowledge would then be easily stolen by the attacker, who will have the possibility to sell this to other players in the same area...just by copying the code in production. In my experience, almost no code in .NET is correctly obfuscated in production. There are many tools that can easily decompile the code in a very intelligible form.

Mário Meyrelles
  • 1,594
  • 21
  • 26
  • It really depends who is the customer, what if the customer of the code is a developer? what if security isn't a concern at all? and even if security is a concern there are multiple ways to exclude the tests from release builds. You make various assumptions but you don't answer the question. – iam3yal May 17 '22 at 21:24
  • If security is not a problem or if there is a good solution like conditional compilation available, I would definitely use the same project to run the tests. Otherwise, the creation of test projects is a necessary evil. If it can be avoided, we should simplify things. In cloud serverless scenarios, I would consider the single-project approach, for example. – Mário Meyrelles May 18 '22 at 10:12
-7

Do you put unit tests in the same project for convenience or do you put them in a separate assembly?

No, never, ever do that. The consumers of your component cannot separate your test code from your production code and therefore, they cannot use it for anything non-trivial.

From the perspective of a security minded consumer, every public symbol in your assembly is part of the attack surface area of your customer's products. Why would they want to use an assembly that includes any non-production security surface area?

SHAME ON YOU IF YOU THINK IT'S OKAY TO INCLUDE UNIT TESTS IN PRODUCTION ASSEMBLIES!

And shame on you if you accept such assemblies for inclusion in your products.


Is it okay to publish your test assemblies? Of course it is, and I consider it to be a best practice. They can be a great aid to customer support, and your customers might also want to incorporate them into their own test environments. Just don't force your test bits on your customers.

jwdonahue
  • 6,199
  • 2
  • 21
  • 43
  • So many down votes and nobody willing to say why. – jwdonahue Feb 03 '22 at 18:14
  • 1
    I would guess the downvotes are not for your opinion but more how you expressed it by using the word shame. It was an instant turn off for me reading it. – Craig Norton Feb 19 '22 at 20:48
  • @CraigNorton Well the cost of gross negligence in the software development community exceeds a trillion dollars per year at this point, so ya, anybody that thinks it's anything less than shameful to ignore common sense security practices, deservers to be made to feel uncomfortable. But I suppose I could reword it. Any suggestions that won't water it down to the point of irrelevance? – jwdonahue Feb 24 '22 at 20:29
  • @CraigNorton now I think of it. It isn't necessarily harmful if the test code is in there for test builds, provided they are not compiled into the released product, but the unit complexity goes up exponentially (generally more test than product code). Tooling could solve that. – jwdonahue Feb 24 '22 at 20:40