5

Let's say I have the following setup:

public interface IFoo
{
    string DoSomething();
    string DoAnotherThing();
}

public sealed class Bar : IFoo
{
    public string DoAnotherThing() => "DoAnotherThing";
    public string DoSomething() => "DoSomething";
}

Using Moq, I would like to mock out one of the methods of Bar, but call the implementation of another one. I know I could do this by creating a wrapper class that delegates to Bar, like so:

public class MockableBar : IFoo
{
    private readonly IFoo _bar;
    public MockableBar(IFoo bar) => _bar = bar;
    public virtual string DoAnotherThing() => _bar.DoAnotherThing();
    public virtual string DoSomething() => _bar.DoSomething();
}

And then mocking it like so:

var fake = new Moq.Mock<MockableBar>(new Bar()) { CallBase = true };        
fake.Setup(_ => _.DoSomething()).Returns("Mock");

Assert.AreEqual("DoAnotherThing", fake.Object.DoAnotherThing());
Assert.AreEqual("Mock", fake.Object.DoSomething());

Is there a more generic way to accomplish this, so I don't have to create a new wrapper class for each of the interfaces I want to test in this mechanism?

John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • Why do you need the wrapper class at all? Can you not just do a partial mock of `Bar` and achieve the same result? – RagtimeWilly Apr 05 '18 at 23:34
  • Why is Bar sealed? That seems to be the problem. – Michael Liu Apr 05 '18 at 23:36
  • Bar is sealed because the class wasn't designed to be inherited from. – John Koerner Apr 05 '18 at 23:38
  • 2
    [A contrary opinion.](https://stackoverflow.com/questions/34827443/should-classes-still-be-sealed-as-a-recommendation?rq=1) Unsealing Bar would make your life a lot simpler. – Michael Liu Apr 05 '18 at 23:46
  • What if generate proxy class (analog of your `MockableBar`) automatically at runtime? Though I'd agree with Michael, making classes sealed without much reason often brings so much pain (not to you, but to users of your library). I hit that so many times that class in third party library which I need to inherit from to achieve my goal, is sealed, though I have never ever thought "I wish that class was sealed, it would have been so beneficial for me to not be able to inherit from it". However, that's opinion-based of course. – Evk Apr 08 '18 at 16:17

2 Answers2

0

You missing some point, I think. There is no need mockablebar. You can mock directly IFoo interface. (Mock works for virtual method and interfaces as well). And where is you need to Barobject, actually you should use IFoo object. When you want to test bar class, your sut (system under test) object is a bar directly.

Note: During test, if you have to create extra class, this means your code is not testable.

If there is usage like that in your code:

public void SomeFunction(Bar bar)
{
   .... Do something
}

You can change like this (and thanks to this, you can mock parameter and easily write test fot method)

public void SomeFunction(IFoo bar)
{
   .... Do something
}

And your test should look like

Mock<IFoo> myMock = new Mock<IFoo>();

myMock.setup(m=>m.DoSomething()).Returns(()=>”some wantted result”);
//Or
myMock.setup(m=>m.DoSomething()).Throws(()=>new Exception(“some message”));

sut = new SomeClass();
sut.SomeFunction(myMock);
assert....
Adem Catamak
  • 1,987
  • 2
  • 17
  • 25
  • I want to mock part of `Bar`, but use the base implementation for other calls, hence why `MockableBar` was created. These aren't quite unit tests, rather they are more sub-system integration tests and I want to validate that `Bar.DoAnotherThing()` is returns the proper values with the subsystem in a certain state. – John Koerner Apr 05 '18 at 22:59
0

If I understand your question correctly, you have a Bar object that implements IFoo. Another object that you are testing depends on Bar, but you want to substitute Bar for a fake for testing.

How about something like:

// Arrange
Mock<IFoo> fooMock = new Mock<IFoo>();
fooMock.Setup(s => s.DoSomething()).Returns("Mock");
// using constructor injection, but hook up your IFoo implementer
// to your testObject however you normally would.
MyClass testObject = new MyClass(fooMock.Object);
// Act
testObject.DoSomethingInvokingIFooDoSomething();
// Assert whatever

Your MyClass object needs to use IFoo rather than Bar for its parameters/variables etc because it should be decoupled and not care how its IFoo provider comes up with the results, just that it can.

Adam G
  • 1,283
  • 1
  • 6
  • 15
  • I am looking for a generic way to solve the problem, so I don't have to create the mockable class every time I want to call an implementation of an interface. I was hoping there would be a way to create something like a `Wrapper` that took a `T` that I could use anywhere I wanted to use this pattern. I updated the sample to have the mockable class take an `IFoo`, to clear it up a bit. – John Koerner Apr 05 '18 at 23:13
  • Your requirement is unclear to me. Each thing you are testing would have specific requirements as to how that mock was setup, which precludes a generic solution. But if you have a number of test cases that share 90% of the setups, you could create a helper CreateDefaultIFooMock() method, then each test can just add the test case specific setups to it. (I have done this with IConfig interfaces where you might be testing specific config properties in a given test but otherwise need sensible defaults for each). – Adam G Apr 05 '18 at 23:31
  • 1
    I want the default behavior to be to call `Bar`'s implementation, but I want to be able to override that behavior. I have accomplished that by creating `MockableBar`. Let's say I have 10 more interfaces where I have similar requirements, I would rather not have to create multiple classes that all delegate to an implementation of those interfaces. I would rather have a way of generically creating a mock that calls an implementation by default and I can override what I need after the fact. – John Koerner Apr 05 '18 at 23:57