views:

187

answers:

6

I have written my units tests, and where external resources are needed it is dealt with by using fakes.

All is good so far. Now i' am faced with the other test phases, mainly integration where i want to repeat the unit test methods against real external resources e.g The Database.

So, What are the recommendations for structuring test projects for Unit Vs Integration testing? I understand some people prefer separate assemblies for unit and Integration?

How would one share common test code between the two assemblies? Should i create a thrid assembly which contains all the Abstract Test Classes and let the unit and integration inherit? I am looking for maximum re-usability...

I hear alot of noise about Dependency Injection (StructureMap), How could one utilise such a tool in the given Unit + Integration test setup?

can anyone share some wisdom? Thanks

+1  A: 

I don't think you should physically separate the two. A good solution is to put the Microsoft.TeamFoundation.PowerTools.Tasks.CategoryAttribute above your tests to identify regular and integration tests. When running tests (even with MSBuild) you can decide to run only the tests you're interested in.

Alternatively you can put them in seperate namespaces.

Gerrie Schenck
A: 

One approach would be to create a separate file with helper methods that would be used across multiple testing contexts, and then include that file in both your unit tests and your functional tests. For the parts that vary, you could use dependency injection - for example, by passing in different factories. In the unit tests, the factory could build a fake object, and in the functional tests it could insert a real object in to your test database.

John Hyland
A: 

Whether you split the tests into two projects or keep them in one might depend on the number of classes/tests you have. Too many classes in a single project would make it difficult to dig through. If you do split them out, helper/common methods could be thrown into a third assembly, or you could make them public in the unit test assembly, and let the integration assembly reference that one. Make things only as complex as you have to.

Pedro
By making the Unit Test methods public, wouldn't i have to declare the same test method twice. Once in the Unit Test and once again in the Integration test, allbeit calling the base method to do the assertion?
If you are referring to the common methods, they could be declared static. Or you could instantiate your helper class. You don't have to derive one class from the other.
Pedro
A: 

On our project we have both integration and unit tests together but in separate folders. Our project layout is such that we have separate assemblies for the main sections (Domain, Services, etc). Each assembly has a matching test assembly. Test assemblies are allowed to reference other test assemblies.

This means Services.Test can reference Domain.Test which makes sense to us because Services references Domain in the actual code.

In terms of reusable pieces we have

  • Builders - These provide a fluent interface for creating the most important/complex objects in our domain. These live in the main test folder for our domain. Our domain test assembly is referenced by all other test assemblies.

  • Mothers - These insert data into the database. They give back an Id for the inserted row which can be used to load the object if required. These live in the main test folder for our services.

  • Helpers - These are guys that do small things throughout our testing. For instance we prefer to allow access to collections via IEnuermable so we have a CollectionHelper.AssertCountIsEqualTo<_T>(int count, IEnumerable<_T> collection, string message) which wraps the IEnumerable in a List and asserts a count. Our Helpers all live in a common test which every other test references.

As for an IoC container if you can use one on your project they can be a huge help not only in testing (via auto mocking) but also in general development. With the overheard of registering everything with the contain though it might be a bit much for just testing.

ShaneC
I take it your unit tests dont touch the database? If so how do fire up a unit test with a mock and how do you fire up a integration test with a database? Are you re-using the same code to execute a unit and integration test. e.g how are you calling this code for both tests..[TestMethod]public void CanGetData(){Assert.IsTrue() //Somehthing}
A unit test by definition does not touch any external resources. And in fact should avoid touching other classes as well (though being dogmatic about this one can be costly). If a test needs to touch the database it becomes an Integration test. I have a base class for integration test classes which provides all the database access.
ShaneC
A: 

After some experimenting this is how you can re-use test methods:

    public abstract class TestBase
    {
        [TestMethod]
        public void BaseTestMethod()
        {
            Assert.IsTrue(true);
        }
    }


    [TestClass]
    public class UnitTest : TestBase
    {
    }

    [TestClass]
    public class IntegrationTest : TestBase
    {
    }

The unit and integration test class will pick up the base class test methods and run them as two separate tests.

You should be able to create a parametised constructor on the base class to inject your mocks or resources.

I think this method can olny be used with classed within the same assembly. So it looks like the single assembly approach will have to do for now.

Thanks for the tips ppl!

Remember, you can have Assert statements in methods that don't have the [TestMethod] attribute. You could thus have two tests perform partially same functionality by calling a third method referenced by both, whether in the same assembly or in a different one.
Pedro
+1  A: 

For code that will be executed in setup & teardown phases, the base class approach would work well. For integration tests, you can extract the functionality of your unit tests into well-parameterized non-test methods (preferably placed in another namespace) and call these "common" methods from both unit and integration tests. Putting unit tests, integration tests and common methods into separate namespaces would suffice, there would be no need for extra assemblies.

henginy