Using Moq for non sealed Concrete Classes

1,552 views
Skip to first unread message

n3sachde

unread,
Jan 19, 2009, 6:26:07 AM1/19/09
to Moq Discussions
Hi

I have a scenario where I need to use a mocked object for "a non
sealed concrete class". creating is for a concrete class a not an
interface.

I know one of answers to my question is a design change or proabably
using an Interface or using patterns like Dependency injection or IOC.
At this moment I cannot refactor my code because of time lines.

Here are more details on my scenario, would appreciate if you can
please assist me.

========== >>>> Class Under Test:

public class ConcreteClass
{

public void MethodToTest()
{

// ========== >>>>This is a dependant class so I want to mock
this <<<<<<<<<< ======
ServiceProxy proxy = new ServiceProxy();
proxy.MethodToMock();

//some other logic in the class
............
}
}

========== >>>>Class To Mock:

public class ServiceProxy()
{
public void MethodToMock()
{
// do something here
}
}

========== >>>>Test Code:

public void MethodToTestTest()
{
var mock = Mock<ServiceProxy>();
mock.Setup(serviceObject => serviceObject.MethodToMock());

// ========== >>>> Calling Concrete Class to test the method
// I dont have an interface or a parameter (no dependency inject
or IOC), how do I connect the mock to my original implementation.

ConcreteClass classUnderTest = new ConcreteClass();
classUnderTest.MethodToTest ();


}

Brian J. Cardiff

unread,
Jan 19, 2009, 6:41:47 AM1/19/09
to moq...@googlegroups.com
If you can't refactor much I think you are a bit stuck.

The minor changes that will allow you to test with a proxyservice are:

a) promote service proxy local variable to a class field. Initialize upon construction. Leave another constructor for testing which will receive a service proxy instance.
b) promote service proxy local variable to a class field. Initialize upon construction. Do nasty things to access fields.
c) (recommended) create a field Func<ServiceProxy> which will act as a factory for that component. On a default constructor leave the classic construction and create another constructor for testing which will receive a Func<ServiceProxy>. Take care about object disposal. This option would be something like this:

public class ConcreteClass
{
     Func<ServiceProxy> factory;
     public ConcreteClass()
        : this( () => new ServiceProxy() )
     {
     }

     public ConcreteClass(Func<ServiceProxy> factory)
     {
           this.factory = factory;
     }

     public void MethodToTest()
     {
        ServiceProxy proxy = factory();

        proxy.MethodToMock();

       //some other logic in the class
       ............
      }
}
public void MethodToTestTest()
{
     var mock = Mock<ServiceProxy>();
     mock.Setup(serviceObject => serviceObject.MethodToMock());

     ConcreteClass classUnderTest = new ConcreteClass(() => mock.Object);
     classUnderTest.MethodToTest ();
}



Brian J. Cardiff
bcardiff(?)gmail.com
.

andreister

unread,
Jan 19, 2009, 10:48:44 AM1/19/09
to Moq Discussions
Hi,

I doubt if testing that code - without refactoring - adds any value in
the long run.

Brian suggested some band aid, but imho it just adds complexity to the
system, and while it might look feasible to allow testing "right now",
the proper solution is to refactor the code.

If you cannot refactor it, don't test it.

Don't fritter away your energy, the *tests* should support the system,
not vice versa. Without proper refactoring, adding methods just for
the sake of testing Something Else looks confusing. Moreover, it could
lead to potentially dangerous situations if someone starts using this
"only for testing" loophole in their code.

Cheers,
Andrew

----------------------------------------------------
http://codevanced.net/ - Advanced solutions in .NET

Brad Stiles

unread,
Jan 19, 2009, 11:11:27 AM1/19/09
to moq...@googlegroups.com
> I know one of answers to my question is a design change or proabably
> using an Interface or using patterns like Dependency injection or IOC.
> At this moment I cannot refactor my code because of time lines.

You could try something like below (exact syntax not checked with
anything). It doesn't change your concrete class to deal with
injection, but still allows testers to do so, and you don't need to
add a new constructor for your Concrete class. Non-test code will use
the proxy created by the class itself, and test code can inject it's
own.

// Class Under Test:
public class ConcreteClass
{

protected _proxy;

public ConcreteClass()
{
_proxy = new ServiceProxy();
}

public void MethodToTest()
{
// This is a dependant class so I want to mock this
_proxy.MethodToMock();
}
}

public class ServiceProxy()
{
public void MethodToMock()
{
// do something here
}
}

//Test Code:

public class ConcreteTester : ConcreteClass()
{
public ConcreteTester(ServiceProxy proxy)
{
_proxy = proxy;
}
}

public void MethodToTestTest()
{
var mock = Mock<ServiceProxy>();
mock.Setup(serviceObject => serviceObject.MethodToMock());

ConcreteClass classUnderTest = new ConcreteTester(mock.Object);
classUnderTest.MethodToTest ();
}

Daniel Cazzulino

unread,
Jan 19, 2009, 3:03:55 PM1/19/09
to moq...@googlegroups.com
protected fields, yuck!
--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471

Brad Stiles

unread,
Jan 19, 2009, 3:19:39 PM1/19/09
to moq...@googlegroups.com
> protected fields, yuck!

It works without having to refactor *other* classes, which is what I
gathered the OP was trying to avoid, if possible. When dealing with
legacy code, I've often found it better to make small sub-optimal
choices, rather than large optimal ones, a choice which might not be
required with new code. If the goal is to get the code under test
with minimal impact to other code, this is one way to do that.

/bs

Andy Sipe

unread,
Jan 19, 2009, 3:54:55 PM1/19/09
to moq...@googlegroups.com
This book:

http://www.amazon.com/Working-Effectively-Legacy-Robert-Martin/dp/0131177052

Has some great tips for handling thorny legacy testing problems like yours.   It is a great read if you spend a lot of time in legacy code that wants/needs tests.   Testing legacy code isn't for the faint of heart, but it can be worth while if the system is going to be around for the long term.   You have to make a lot of compromises that you might otherwise shy away from.

Note:  It has been a while, but I don't think the book covers C# directly.   It does cover java and C++ and the style is easily applied to almost any language.

-andy

Daniel Cazzulino

unread,
Jan 19, 2009, 4:02:43 PM1/19/09
to moq...@googlegroups.com
why not provide a new protected ctor instead??

public class ConcreteClass
{

    private _proxy;

    public ConcreteClass() : this(new ServiceProxy())
    {
    }

    protected ConcreteClass(ServiceProxy proxy)
    {
         _proxy = proxy;
    }



Brad Stiles

unread,
Jan 19, 2009, 5:54:41 PM1/19/09
to moq...@googlegroups.com
> why not provide a new protected ctor instead??

That's another way, though the test would still have to create a derived
class to use it, since it's protected. I don't see much advantage
either way, other than the amount of additional code.

/bs

Daniel Cazzulino

unread,
Jan 20, 2009, 12:15:16 AM1/20/09
to moq...@googlegroups.com
protected ctor would pass fxcop ;)

Brad Stiles

unread,
Jan 20, 2009, 8:29:47 AM1/20/09
to moq...@googlegroups.com
> protected ctor would pass fxcop ;)

True, but then so would:

private ServiceProxy _proxy;
protected Proxy { get { return _proxy; } set { _proxy = value; } }

Again, both provide what I thought the OP was requesting, i.e. a way
to test the consumer of the proxy without having to finagle other code
throughout the application. Both require that the test derive from,
and add code to, the class under test solely for the purpose of
testing that class, but from what I've seen, that's a consequence of
working with legacy code.

Which option one chooses would seem to me to be a matter of taste, as
I don't discern any compelling advantage or disadvantage to either
one. The protected property version feels simpler to *me*, but I can
recognize that might not be true for everyone.

/bs

Daniel Cazzulino

unread,
Jan 20, 2009, 10:40:14 AM1/20/09
to moq...@googlegroups.com
now that's a better alternative.
what I wouldn't like is to make it sound like directly exposing fields is Ok and kind of recommended when working with legacy code...

and yes, in this it's a matter of style.

cheers!

Brad Stiles

unread,
Jan 20, 2009, 10:59:18 AM1/20/09
to moq...@googlegroups.com
> what I wouldn't like is to make it sound like directly exposing fields is Ok
> and kind of recommended when working with legacy code...

Ah, I understand now. I wasn't trying to make that case. I guess I
was leaving the "refinement" part of it as an exercise for the reader.
At least, that's my excuse...

/bs

Reply all
Reply to author
Forward
0 new messages