4

I'm looking for a good way to organize my unit tests in a .NET project. Right now, I have one TestClass per application class, with multiple tests for each method. Although I am using TestCategory to categorize each TestMethod by the application class method it tests, finding my test methods is becoming ungainly.

I'm considering splitting my test classes into partial classes - one partial class per application class method. This means that I can have multiple TestMethod in one dedicated file per method, without having to hunt through a large file to find them.

Are there any pitfalls to this approach? Are there better ways of handling large test classes in .NET and Visual Studio?

Edit: I am using IoC (we're using Castle.Windsor for DI outside of the tests) and we're using Moq for mocking capabilities. Tests are initialized with TestInitialize.

  • 1
    You can create a test class for each method. For example, you have class `C1` with methods `M1` and `M2`. Create 2 test classes, `C1_M1_Test` and `C1_M2_Test`. – Massimiliano Kraus May 18 '16 at 14:20
  • Consider splitting your classes under test into multiple smaller classes instead of splitting your tests. – Carra May 18 '16 at 14:46
  • @Carra No...one method may have multiple tests. If a class has three methods, and each method has six tests....that's eighteen tests in one test class. Changing the application classes doesn't really address the issue - it's addressing the scale of growth at the wrong side of the equation. –  May 25 '16 at 17:53
  • @Carra And honestly....I realize, as you do, that the scalability isn't the root problem. It's the fact that we have to worry about control flow in our functions. One function may throw three different exceptions based on its input. It may return a null object, or a non-null object. I hate to dismiss your comment, as you aren't actually wrong....it's just difficult to separate some of these concerns without union types, immutable objects, and referentially transparent methods. It's doable, but probably not worth the cost to my team and me. –  May 26 '16 at 01:04

2 Answers2

2

Take a look at my answer C# ASP.NET MVC Controller unit test. The gist of it is:

  • a static class that wraps all the tests for a given system under test.
  • a test class for each test scenario you are running that inherits from a base class

The other nice about this setup is that it gives you a nice tree of tests, if you are using the resharper unit test session to be able to easily find your test.

As for the first answer, you should not be using a DI framework in your tests. All external dependencies should be mocked/faked so that you are only testing the system under test.

And for using partial classes. See Are C#'s partial classes bad design?

I agree with Carra, using partial classes just to split a long class is considered bad design. If your class so large, maybe it needs to be broken up.

Community
  • 1
  • 1
Fran
  • 6,440
  • 1
  • 23
  • 35
  • Hmm. I may consider the inheritance pattern, but I don't use Resharper. I'm not sure if the static class is necessary in my case. We are using mocks, but we aren't using DI in the tests themselves (we are in the application). I suppose the real problem I'm trying to solve is the lack of nested test specs - I feel that the class-per-method paradigm is a very poor solution for this. –  May 18 '16 at 15:37
  • Essentially....I realize, I'm looking for something similar to the `describe` functionality in [Mocha](https://mochajs.org/) - a way to logically structure my tests without having to jump through hoops to do so. –  May 18 '16 at 15:41
  • The static class isn't for resharper, it's to logically group all test scenarios of a specific class. you may have more than 1 class per method depending on any branching logic in that method. you may also group a number of testing under 1 class. Note in my example how I have multiple tests in my first instance because they won't change of the course of the tests. then i break out specific scenarios to there own tests. – Fran May 18 '16 at 16:03
  • I ended up using the technique described [in this article](http://haacked.com/archive/2012/01/02/structuring-unit-tests.aspx/), which is similar to what you suggested, except without the unnecessary static wrapper class. I'm using the base class as the wrapper class. Thus, I have initialization in one place for all tests, I have "describe" functionality (easy to find tests in code), I can still mirror my target project (one test file per app file), I get free grouping in the test explorer, and I run into no disadvantages. A great deal, overall! –  Jun 03 '16 at 19:03
0

I would keep your tests simple and concise. Separating your tests could be beneficial but where do you Initialize your test code? Are you using Inversion of Control to do work that the other tests should have already done? If so then you might want to look at [TestInitialize] and start organizing your dependencies.

Here is what I mean for centralizing TestInit

[TestClass]
public class UnitTestWebsiteBuilderPattern
{
    private IHtmlInputService _htmlInputService;
    private IHtmlControlService _htmlControlService;
    private IHtmlMenuControlService _htmlMenuControlService;
    private IHtmlConditionalInputService _htmlConditionalInputService;
    private IHtmlPanelService _htmlPanelService;
    private IHelpIconService _helpIconService;
    private IHtmlModalService _htmlModalService;

    [TestInitialize]
    public void Init()
    {
        _helpIconService = new HtmlHelpIconService();

        _htmlInputService = new HtmlInputService(_helpIconService);
        _htmlPanelService = new HtmlPanelService(_htmlInputService);

        _htmlModalService = new HtmlModalService(_htmlPanelService);
        _htmlControlService = new HtmlControlService(_htmlPanelService);

        _htmlMenuControlService = new HtmlMenuControlService();
        _htmlConditionalInputService = new HtmlConditionalInputService();

    }
  • I am already doing this, using Moq. The problem with multiple classes here is that I'd end up repeating this code everywhere (unless I inherited from a base test class that matches the application class, or something). –  May 18 '16 at 15:29
  • you can use di to centralize your app_start for your unit tests private static void RegisterServices(IKernel kernel) –  May 18 '16 at 20:04
  • since you are using castle Windsor you can moq out Expected Results and Assert your Expectation is correct. As for partial classes for testing to somehow make testing more fun and more simple, redesign. http://www.codeproject.com/Articles/5772/Advanced-Unit-Test-Part-V-Unit-Test-Patterns –  May 25 '16 at 16:00