views:

114

answers:

4

I am wondering if Unittesting and using statements can really go hand in hand as there is no way to mock the disposable object instantiated in the using statement. How would I be able to effectively unittest a method containing the following using statement?

public void MyMethod()
{
   using(MyDisposableClass disp = new MyDisposableClass())
   {
       ...
   }
}

Are using statements simply forbidden when you are unit-testing?

Any comments appreciated.

+4  A: 

No, using statements are certainly not forbidden. But what does MyDisposableClass actually do? It strikes me that this isn't really a matter of the using statement being a problem - it's a matter of the method creating a new object which you want to mock - that's the problem.

Do you genuinely need to mock MyDisposableClass? Can it be passed into MyMethod instead of being created inside it? As ever, the trick is to work out how to hook into the process and inject your own objects when you need to...

Jon Skeet
MyDisposableClass is really an adapter to an external system that I need to Connect(), Login() and LogOut() on dispose. If I ship it as a parameter I run into a problem in the parent method right?
Fadeproof
Certainly *something* needs to create it. You basically need to work out the best hook for that. Unfortunately it's hard to tell you *exactly* where to inject the object without knowing more about your system than we probably have time to see here :(
Jon Skeet
+1  A: 

Using the factory pattern and/or dependency injection pattern will greatly simplify the way you unit test methods that instantiate their own resources.

Here's a good read on the subject:

Pop Catalin
+2  A: 

Since you want to mock the resource class I assume you already have

interface IResource : IDisposable
{
        void DoSomething();
}

class DisposableResource : IResource
{
    public void Dispose()       {  Console.WriteLine("That's it. I'm outta here!");  }
    public void  DoSomething()  {  Console.WriteLine("Hard work this");  }
}

To be able to inject the obj, you need a seam.. i.e. GetResource()

class MyClass
{
    protected virtual IResource GetResource()
    {
        return new DisposableResource();
    }
    public void MyMethod1()
    {
        using (IResource r = GetResource())
        {
            r.DoSomething();
        }
    }
}

In your test code, simply subclass and override GetResource() to return a mock.

class MySubClassForTest : MyClass
{
    protected override IResource GetResource()
    {
        return new MockResource();
    }
}
class MockResource : IResource    // or use a mock framework to create one
{
    public void  DoSomething()        { Console.WriteLine("Me work?"); }
    public void  Dispose()            { Console.WriteLine("Disposed Mock!"); }
}

That's it.

 MyClass obj = new MyClass();           // production code
 obj.MyMethod1();

 obj = new MySubClassForTest();         // test code
 obj.MyMethod1();
Gishu
+1  A: 

TypeMock will allow you to mock this. It works by modifying the IL on the fly and thus has no problems mocking stuff you otherwise can't mock.

But even with TypeMock you should still take a look at what Jon Skeet and Pop Catalin are saying above. Your code will be easier to maintain, if you try to reduce the number of dependencies.

Brian Rasmussen