Vinicius Seganfredo
Vinicius Seganfredo

Reputation: 1754

How do I mock a class without an interface?

I am working on .NET 4.0 using C# in Windows 7.

I want to test the communication between some methods using mock. The only problem is that I want to do it without implementing an interface. Is that possible?

I just read a lot of topics and some tutorials about mock objects, but all of them used to mock interfaces, and not the classes. I tried to use Rhino and Moq frameworks.

Upvotes: 128

Views: 192297

Answers (10)

Connor Ivy
Connor Ivy

Reputation: 21

You can mock classes without an interface using the library MockMe (disclaimer: I am the author).

Unlike other mocking frameworks that can only be used on interfaces or virtual methods, MockMe allows you to also mock sealed classes and non-virtual methods.

The api for using it is (hopefully) pretty intuitive

using MockMe;

var mock = Mock.Me(default(MyRepo)); // rebuild test project after writing this to help IDE fill in IntelliSense

mock.Setup.ExpensiveDatabaseCall().Returns(99);

MyRepo myRepo = mock.MockedObject;
var result = myRepo.ExpensiveDatabaseCall();

Assert.Equal(99, result);
mock.Assert.ExpensiveDatabaseCall().WasCalled();

Upvotes: 2

Mihail Vladov
Mihail Vladov

Reputation: 538

It is a bit old question but nevertheless. There are powerful mocking frameworks these days that are capable of mocking concrete classes like JustMock and Typemock.

Upvotes: 4

Anang Satria
Anang Satria

Reputation: 1286

I think it's better to create an interface for that class. And create a unit test using interface.

If it you don't have access to that class, you can create an adapter for that class.

For example:

public class RealClass
{
    int DoSomething(string input)
    {
        // real implementation here
    }
}

public interface IRealClassAdapter
{
    int DoSomething(string input);
}

public class RealClassAdapter : IRealClassAdapter
{
    readonly RealClass _realClass;

    public RealClassAdapter() => _realClass = new RealClass();

    int DoSomething(string input) => _realClass.DoSomething(input);
}

This way, you can easily create mock for your class using IRealClassAdapter.

Hope it works.

Upvotes: 28

Marzouk
Marzouk

Reputation: 2714

I faced something like that in one of the old and legacy projects that i worked in that not contains any interfaces or best practice and also it's too hard to enforce them build things again or refactoring the code due to the maturity of the project business, So in my UnitTest project i used to create a Wrapper over the classes that I want to mock and that wrapper implement interface which contains all my needed methods that I want to setup and work with, Now I can mock the wrapper instead of the real class.

For Example:

Service you want to test which not contains virtual methods or implement interface

public class ServiceA{

public void A(){}

public String B(){}

}

Wrapper to moq

public class ServiceAWrapper : IServiceAWrapper{

public void A(){}

public String B(){}

}

The Wrapper Interface

public interface IServiceAWrapper{

void A();

String B();

}

In the unit test you can now mock the wrapper:

    public void A_Run_ChangeStateOfX()
    {
    var moq = new Mock<IServiceAWrapper>();
    moq.Setup(...);
    }

This might be not the best practice, but if your project rules force you in this way, do it. Also Put all your Wrappers inside your Unit Test project or Helper project specified only for the unit tests in order to not overload the project with unneeded wrappers or adaptors.

Update: This answer from more than a year but in this year i faced a lot of similar scenarios with different solutions. For example it's so easy to use Microsoft Fake Framework to create mocks, fakes and stubs and even test private and protected methods without any interfaces. You can read: https://learn.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes?view=vs-2017

Upvotes: 2

Tim Ottinger
Tim Ottinger

Reputation: 1452

If worse comes to worse, you can create an interface and adapter pair. You would change all uses of ConcreteClass to use the interface instead, and always pass the adapter instead of the concrete class in production code.

The adapter implements the interface, so the mock can also implement the interface.

It's more scaffolding than just making a method virtual or just adding an interface, but if you don't have access to the source for the concrete class it can get you out of a bind.

Upvotes: 5

Justin Pihony
Justin Pihony

Reputation: 67075

Simply mark any method you need to fake as virtual (and not private). Then you will be able to create a fake that can override the method.

If you use new Mock<Type> and you don't have a parameterless constructor then you can pass the parameters as the arguments of the above call as it takes a type of param Objects

Upvotes: 100

Rustem Zinnatullin
Rustem Zinnatullin

Reputation: 403

If you cannot change the class under test, then the only option I can suggest is using MS Fakes https://msdn.microsoft.com/en-us/library/hh549175.aspx. However, MS Fakes works only in a few editions of Visual Studio.

Upvotes: 9

Thomas Weller
Thomas Weller

Reputation: 11717

The standard mocking frameworks are creating proxy classes. This is the reason why they are technically limited to interfaces and virtual methods.

If you want to mock 'normal' methods as well, you need a tool that works with instrumentation instead of proxy generation. E.g. MS Moles and Typemock can do that. But the former has a horrible 'API', and the latter is commercial.

Upvotes: 7

matt
matt

Reputation: 9401

Most mocking frameworks (Moq and RhinoMocks included) generate proxy classes as a substitute for your mocked class, and override the virtual methods with behavior that you define. Because of this, you can only mock interfaces, or virtual methods on concrete or abstract classes. Additionally, if you're mocking a concrete class, you almost always need to provide a parameterless constructor so that the mocking framework knows how to instantiate the class.

Why the aversion to creating interfaces in your code?

Upvotes: 33

Roy Dictus
Roy Dictus

Reputation: 33139

With MoQ, you can mock concrete classes:

var mocked = new Mock<MyConcreteClass>();

but this allows you to override virtual code (methods and properties).

Upvotes: 32

Related Questions