简体   繁体   中英

Rhino mocks and objects created in using statements

Most of the time when we use Rhino mocks it works well, but we have problems mocking objects created using the using statements.

We have a WCF proxy that is implemented as follows:

public class MyProxy : System.ServiceModel<IMyProxy>, IMyProxy
{
    public Response DoWork(Request request)
    {
         return base.Channel.DoWork(request);
    }
}

Normally in our business layer we would have a property:

 IProxy MyProxy;

Which we could set as being the mocked interface.

But when we use a using statement, our business layer looks like this:

using (MyProxy proxy = new MyProxy())
{
}

Which instanciates the concrete implementation of the class.

How do we get the business layer to use the mock created with Rhino mocks?

Edit

It turned out that you should not use using statements with wcf proxies http://msdn.microsoft.com/en-us/library/aa355056.aspx

Inject Func<IProxy> into your class, and store it in a field.

Your code then becomes

public class MyClass
{
    private readonly Func<IProxy> createProxy;

    public MyClass(Func<IProxy> createProxy)
    {
        if (createProxy == null)
            throw new ArgumentNullException("createProxy");
        this.createProxy = createProxy;
    }

    public void DoSomething()
    {
        using (IProxy proxy = this.createProxy())
        {
            ...
        }
    }
}

Your unit test then looks like this:

[Test]
void MyClass_does_something()
{
    var proxyStub = MockRepository.CreateStub<IProxy>();
    var myClass = new MyClass(delegate { return proxyStub; });

    myClass.DoSomething();

    // make assertions...
}

Note that there more relationships other than simple "A needs B" and "A creates B".

I have assumed that IProxy derives from IDisposable here. This is a bit of a simplification: the proxy instance may also have disposable dependencies of its own created by the container. You can't always just assume that those dependencies need to be disposed at the same time as the requested object. That's why it is better to use Owned<T> as illustrated in the blog post I linked above.

I doubt that it's the using statement that's the problem here - I expect it's the fact that it's using a constructor.

One way round this is to use dependency injection to give the object a provider (aka factory) for the object in question. In tests, you can then give it a provider which returns your mock object.

I would change the code to use an IoC system, to look more like:

using (IMyProxy proxy = IoC.Resolve<IMyProxy>())
{
}

With IMyProxy inheriting IDisposable . Then in the test environment, set up the IoC to return the mock instead of the runtime type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM