Freigeben über


Unused referenced assemblies don't actually stick around

Thanks to all who joined us in the C# & Unit Testing chat today.  It was fun and we'll try to do it again soon.  For those who weren't able to make it, you should be able to see a transcript of it over on this site sometime soon. 

One of the questions asked was how we typically set up our unit tests in relation to our projects.  I primarily try to isolate my unit tests into their own project/assembly as much as possible.  But I have had a few projects where I really needed to test the internal methods and my only option was to make the tests a part of the project itself.  I didn't want to end up having to leave the tests in the final “shipped” assembly though, so I created a folder for all my tests to reside in.  When I wanted to stop compiling the tests into the assembly, I could just remove the folder from the project. 

The usual question I get in response to this is “you also have to remove the reference to NUnit, right?” or something along the lines of Lance's thinking on this post.  The answer is no. The compiler only emits assembly refs to those assemblies the code you're compiling actually uses. 

Here's a simple example.  Compile the following code (e.g. csc /t:library library.cs):

     public class Library {
        public static void Method() {
            System.Console.WriteLine("In Library code");     
        }
    }

and now compile the client code that uses this library (e.g. csc /r:library.dll client.cs):

     class Client { 
        static void Main() {
            System.Console.WriteLine("In Client code"); 
            Library.Method(); 
        } 
    }

Now you can run ILDASM on your client.exe file and press Ctrl+M to bring up the Metainfo dialog.  You'll find an assembly ref for the Library assembly there.  It'll look something like the following:

     AssemblyRef #2
    -------------------------------------------------------
     Token: 0x23000002
     Public Key or Token:
     Name: library
     Major Version: 0x00000000
     Minor Version: 0x00000000
     Build Number: 0x00000000
     Revision Number: 0x00000000
     Locale: 
     HashValue Blob:
     Flags: [none] (00000000)

If you go ahead and comment the 'Library.Method();' line in client.cs, rebuild it using the same command-line (including the reference to library.dll), and run ildasm on it again, you'll find that the assembly ref is no longer listed. 

All that said, I rarely end up going this route whenever I'm working on a project I'm using TDD on anymore.  When I first started playing around with the idea of unit testing and TDD, I was always inclined to want to test the internal methods of the code I'm working on.  Nowadays, I end up focusing way more on the public interface and try to make everything a library.  Doing so somewhat pushes me to decouple more and more and it forces me to think and design the interfaces to the objects I'm creating in a cleaner way.

Comments

  • Anonymous
    March 18, 2004
    Wouldn't using a #define accomplish much the same thing, and without needing to modify the project/solution when you do a release build? You can do something like...

    #if DEBUG
    // all the unit testing code in here

    #endif

    When you build the release assemblies none of the unit testing references should show up.
  • Anonymous
    March 18, 2004
    Sure, I didn't mean to say it wouldn't. I've actually done it both ways. It's pretty much a matter of preference. When I've done it conditionally, I've used a specific symbol referring to tests though instead of DEBUG (e.g. #if UNITTESTING) so I could run my tests against release bits as well. But again, all of these would work fine. Thanks Dave...
  • Anonymous
    November 15, 2006
    Thanks to all who joined us in the C# & Unit Testing chat today.  It was fun and we'll try to do it again soon.  For those who weren't able to make it, you should be able to see a transcript of it over on this site sometime soon.  I do not agree. Go to http://www.hotelsjobs.info/crucible_Cyprus/elude_Republic%20of%20Cyprus/beagle_Pafos_1.html