Beginner xunit ? - How to best structure your test.

Sep 15, 2009 at 7:12 PM

Guys/Gals i have a very general question. Sorry if this is a stupid question. I'm just getting started with Unit Testing. What is the best way to structure your code so when you move it between environments your test code won't get compiled into the production executables? Should you structure your test kind of like MSTest does and just create an entirely seperate project to house your test? I think the structure i like best is to have each test below or above your function your testing but then your test code will then moved to production. You could also possibly create seperate classes in your project to do the same thing so you don't mix regular code with test code but then again your going to be moving your test to production which seems to not be a good idea. Also this would mean we would have to deploy xunit.dll. Any help would be appreciated.

Thanks,

Ncage

Sep 16, 2009 at 11:01 AM

Hi Ncage,

The xUnit Design Patterns book covers the myriad tadeoffs involved to a degree, as does the Feathers book.

I'm also interested in a proper in depth answer to this based on 2009 knowledge, especially in the context of C#3+ language features and xUnit.net.

You definitely don't want to get into a situation where you have Test Code In Production in any shape or form.  This is what drives people toward the general policy of housing things in a separate binary.

There are a number of issues in play, many of which you have alluded to:

1) Dependecy on xunit.dll

2) Bigger code / Longer load times

3) Having to expose more IP by having to make stuff private or internal

4) Having to manage InternalsVisibleTo in the face of Strong Naming (dont do it)

5) Having contorted classes just to support testing and/or the risk of code that's only there to support tests getting into production

6) Having to suffer random build breaks because publicize.exe falls over (when using Test References/Private Accessors/publicize.exe)

7) Having dependencies on VSTT on build agent boxes because one used Private Accessors (when using Test References/Private Accessors/publicize.exe)

There is the notion of a test stripper (http://xunitpatterns.com/test%20stripper.html) which would remove test related classes and the dependency on things like xunit.dll, but I'm not aware of one for .NET, and searching for anything involving Strippers on this here net be problmatic.

See the sample below for references to Approaches.

Summary of plusses/minuses of putting stuff in the same bin:

+ You can nest test classes into classes [Approach5] and/or use partial classes [Approach1,Approach2] to give access to privates instead of having to use stuff like:

   * MsTest's 'Test References' stuff (using publicize.exe to generate a Private Accessor per class which uses reflection to access private stuff) [Approach3]

   * Having a hand-written 'For Test Only' extension or derived class which exposes stuff needed for tests but would be redundant and/or potentially damaging to have in a final binary [Approach2A,Approach2B]

   * Another idea is http://stackoverflow.com/questions/1043899/non-code-generated-forwarding-shim-for-testing-private-methods

+ You dont need to use InternalsVisibleTo (which gets messy with strong naming] to grant access to non-public stuff [without having to pollute your interface by making it public) [Approach4]

- Potential for Test Code in production

- Need to use a Test Stripper or conditional compilation (I dont believe in using DEBUG for this - I want my tests to be runnable in both release and debug[1]

Based on the above, my considerations in your decision would be:

- InternalsVisibleTo is full of holes and there is a lot of consensus on not using it

- You dont want to have a dependency on xunit.dll -- But how are you going to remove that?

- If you use conditional compilation, it should be based on something other than just DEBUG

- You could use a Test Stripper if you had one, and it should a) remove the ref to the DLL b) remove classes with methods with FactAttribute-derived tags c) probably remove other Fto methods or classes

- You really dont want to get into using MSTest Test References/Private Accessors/publicize.exe) for so many reasons

I highly recommend the Meszaros book for helping one think through all of this stuff (I read Osherove's book too, which is worthy and an easier read but not as deep and neutral as xUnit Test Patterns).

Bottom line:

1. The Simplest Thing That Could Possibly Work is separate assemblies

2. Separate assemblies are not a perfect answer, so lots of people go down rabbit holes of hacks to make that work

3. Not many people use test code in the SUT, and of those, many people are leaving themselves open to a variety of Test Code In Production issues

I'd love to hear more on this, because I'm not happy with my answers and/or the currrent state of play on this.

--Ruben

 

using System;

using System.Runtime.CompilerServices;

using Xunit;

 

namespace Approach1

{

    namespace SutAssembly

    {

        partial class A

        {

            private void F1()

            {

            }

 

            internal void F2()

            {

            }

        }

 

    #if !STRIP_TESTS

        partial class A // FTO stuff

        {

            public void CallF1()

            {

                F1();

            }

 

            public void CallF2()

            {

                F2();

            }

        }

    #endif

    }

 

    namespace TestAssembly

    {

        using SutAssembly;

        public class WhenAccessingPrivates

        {

            [ Fact ]

            public void CanAccessF1AndF2()

            {

                var a = new A();

                a.CallF1();

                a.CallF2();

            }

        }

    }

}

 

namespace Approach2A

{

    namespace SutAssembly

    {

        public partial class A

        {

            private void F1()

            {

            }

 

            private void F2()

            {

            }

        }

 

        class FtoAttribute : Attribute { }

 

        public partial class A // FTO stuff

        {

            [ Fto ]

            public void CallF1()

            {

                F1();

            }

 

            [Fto]

            public void CallF2()

            {

                F2();

            }

        }

        // Now we can look for FtoAttribute to either implement a Test Stripper or verify FTO code has been removed

    }

 

    namespace TestAssembly

    {

        using SutAssembly;

        public class WhenAccessingPrivates

        {

            [Fact]

            public void CanAccessF1AndF2()

            {

                var a = new A();

                a.CallF1();

                a.CallF2();

            }

        }

    }

}

 

namespace Approach2B

{

    namespace SutAssembly

    {

        public class A

        {

            private void F1()

            {

            }

 

            private void F2()

            {

            }

 

            class FtoAttribute : Attribute { }

 

            [Fto]

            public class A2 : A

            {

                [Fto]

                public void CallF1()

                {

                    F1();

                }

 

                [Fto]

                public void CallF2()

                {

                    F2();

                }

            }

            // Now we can look for FtoAttribute to either implement a Test Stripper or verify FTO code has been removed

        }

    }

 

    namespace TestAssembly

    {

        using SutAssembly;

        public class WhenAccessingPrivates

        {

            [Fact]

            public void CanAccessF1AndF2()

            {

                var a = new A.A2();

                a.CallF1();

                a.CallF2();

            }

        }

    }

}

 

namespace Approach3

{

    namespace SutAssembly

    {

        public class A

        {

            private void F1()

            {

            }

 

            private void F2()

            {

            }

        }

    }

 

    namespace PrivateAccessorAssembly

    {

        using SutAssembly;

        // IN ANOTHER ASSEMBLY

        // Test References generate DLLs containing code like this via a Shadow MSBuild task that generates an accessor DLL using a tool called Publicise.exe

        public class A_Accessor

        {

            public A_Accessor(A a)

            {

            }

 

            public void F1()

            {

                // uses reflection to call F1

            }

 

            public void F2()

            {

                // uses reflection to call F1

            }

        }

    }

 

    namespace TestAssembly

    {

        using SutAssembly;

        using PrivateAccessorAssembly;

 

        public class WhenAccessingPrivates

        {

            [Fact]

            public void CanAccessF1AndF2()

            {

                var a = new A();

                var aAccessor = new A_Accessor(a);

                aAccessor.F1(  );

                aAccessor.F2(  );

            }

        }

    }

}

 

namespace Approach4

{

    namespace SutAssembly

    {

        [ assembly:InternalsVisibleTo( "TestAssembly" ) ]

        public class A

        {

            internal void F1()

            {

            }

 

            internal void F2()

            {

            }

        }

    }

 

    namespace TestAssembly

    {

        using SutAssembly;

 

        public class WhenAccessingPrivates

        {

            [Fact]

            public void CanAccessF1AndF2()

            {

                var a = new A();

                a.F1();

                a.F2();

            }

        }

    }

}

 

namespace Approach5

{

    namespace SutAssembly

    {

        class A

        {

            public void F1()

            {

            }

 

            void F2()

            {

            }

 

            // Need to use either an FtoAttribute based Test Stripper, conditional compilation, a Test Stripper based on the presence of FactAttribute to remove this

            public class WhenAccessingPrivates

            {

                [Fact]

                public void CanAccessF1AndF2()

                {

                    var a = new A();

                    a.F1();

                    a.F2();

                }

            }

        }

    }

}

Sep 18, 2009 at 3:42 AM
Edited Sep 18, 2009 at 3:45 AM

Wow Ruben...EXCELLENT POST!!! I want to think you very much for the time you took in posting your thoughts. I definitely will save this for later reference. I thought it was something that there would be a simple solution. Apparently not. It sounds like something that no matter which route you go down there is no perfect solution. I'm just getting into XUnit using StructureMap for dependency inj. I found that i hated MSTest. Hopefully they make it better in VS 2010. I do love the ability to do code coverage automatically though with MSTest.

I am finding out Unit testing is quite the complex subject to do right. I work on internal apps at my company that have VERY data centric logic. I created a demo for my manager on what MSTest could do. He was very impressed but i explained to him i needed to get educated before we go down that path so we wouldn't spend more time maintaining test than we do code. Currently reading "The Art of Unit Testing". So for its been pretty good. Only on the 2nd chapter. I just don't know how unit testing will fit into our heavily data centric app. We definitely are in a situation where people are horrified to change some of the code in our system because its so complex. You will be working on a bug and you know the code your adding  will fix the current problem but the code is used in so many ways with so many different situations that your in fear your going to mess something up. I'm really trying to get us out of this situation.

Anyways i digress. Thanks for he excellent post again you touched on so many good points and it gives me something to chew on. Hopefully once i'm done with the book i'm reading i will be better armed to make some of these difficult decisions.

I think the best solution (if it was available) would be the "Stripper" type of utility that you were talking about that would take out all the references for testing dlls and remove all the emded test code. Guess we need to open a new project to create one ;)

Sep 18, 2009 at 8:13 AM
Edited Sep 18, 2009 at 11:46 AM

Thanks for the flattery and the opportunity to clarify my thoughs by writing them down - I've been mulling this around for a while and have just read the Osherove book followed by the first 800 pages xUnit Patterns. When I've finished my re-read of WEwLC I'll hopefully have a clearer picture.

I wouldnt even go as far as disparaging MSTest - The point is that xUnit.net is far cleaner and always will be as MSTest, NUnit and MbUnit are always going to have a lot of baggage.  Thankfully the guys seem to be doing a great job on batting back stuff around here in order to keep things clean.  You using Resharper or TD.NET or just the raw GUI runner?

You seem to be taking a good approach to introducing Unit Testing - it's definitely easy to do wrong, even if something is better than nothing. DI is obviously the key to it all - you'd be surprised how well it works with even small apps (Agile Principles Patterns and Techniques is a great book in the space BTW). I've never been sold on the value of code coverage, but that's just me. I've definitely been in that paralysis though fear of change place and thankfully there is light on the other side :D

The Osherove book is a good read, and is great for getting you thinking through things but be careful taking everything at face value from it - lots of it grated with me and it was a relief to read a more neutral presentation in xUnit Patterns. Its been a while since I read the Feathers book but it's definitely a must-read -- it'll give you a great set of ideas for how to approach getting code under test.  I highly recommend getting it for your context. Another great (and thankfully small) book is Beck's TDD: By Example -- but its more about about greenfield TDD than what you're dealing with. IIRC the Osherove book shuffles around your question a bit in later chapters.

I'll monitor http://xunitcontrib.codeplex.com/ for your patch containing xUnit-Stripper. I will be the first user - it seriosuly wouldnt be hard to knock up with Cecil as a little Saturday project.

Sep 18, 2009 at 3:02 PM

@ ncage1974

There are at least two paths to unit testing:

(1) write your code; write your unit tests.          test after coding

(2) TDD (test driven development, a.k.a. "test before testing" and other names like "agile programming")

     in (2), you actually write your test first.  it will initially fail.
     then you write your code with the intent that your test will pass.

     the benefit is that you have put more thought in up front and should, in theory, produce better code.

 ---

even in (1), it is best that your initial tests fails; you need to know that your test can fail, otherwise, it is not a useful test.

 ---

in both (1) and (2), you will code probably an average of four tests for every production routine that you code.

your tests will not always be perfect.  you will assume that they are because you have run them successfully.

later, some tweak to your production code will cause the test to fail (or not fail) and you will realize that your set of tests was flawed.

 ---

generally, your tests will save you time because you will have automated a lot of tests that you would normally perform manually.

 ---

even if you write perfect production code, your tests will still protect you.  For example, assume that your production code was developed under .Net 3.5 Framework.

along comes .Net 4.0 ..... you run your tests and they fail because something different in .Net 4.0 has broken them.

the advantage is you found out about the problem between you shipped your code to your end users ... you saved yourself embarrassment and your end users aggravation.

 

regards ~~ gerry (lowry)

Nov 26, 2009 at 2:21 PM

Update: Have been down this road a bit.

Have implemented a test stripper with Mono.Cecil, but its not perfect yet so not publishing.

http://bytes.com/topic/net/answers/444853-conditional-assembly-reference says that redundant references are automatically removed in a release build, so conditional compilation doesnt have the shortcoming I thought it had in my context of me having to ship xunit.dll etc.

A potential half way house is to have a NOFTO define and then define that via http://stackoverflow.com/questions/479979/msbuild-defining-conditional-compilation-symbols in your final build, but dont define it in your CI build.