abstracting an interface to a class that has extension methods - c#

How do I replace a concrete class with its interface for the purpose of unit testing if I am using extension methods in that class?
I've got a method:
[HttpGet]
[Route("/yoyo/{yoyoId:int}/accounts")]
public ResponseYoyoEnvelope GetAccountsByYoyoId([FromBody] RequestYoyoEnvelope requestYoyoEnvelope, int yoyoId)
{
var responseYoyoEnvelope = requestYoyoEnvelope.ToResponseYoyoEnvelope();
// get our list of accounts
// responseEnvelope.Data = //list of accounts
return responseYoyoEnvelope;
}
I'd like to replace:
RequestYoyoEnvelope requestYoyoEnvelope
with an abstraction:
IRequestYoyoEnvelope requestYoyoEnvelope
however, ToResponseYoyoEnvelope is an extension method.
How do I replace a concrete class with its interface for the purpose of unit testing if I am using extension methods in that class?

You can write the extension method against the interface rather than the concrete class:
public static class Class2
{
public static void Extension(this ITestInterface test)
{
Console.Out.WriteLine("This is allowed");
}
}
Then you can do:
// "Test" is some class that implements the ITestInterface interface
ITestInterface useExtensionMethod = new Test();
useExtensionMethod.Extension();
Note too that this'll still work even if useExtensionMethod isn't explicitly of type ITestInterface:
Test useExtensionMethod = new Test();
useExtensionMethod.Extension();
There's controversy about whether this represents a Decorator pattern but keep in mind at a minimum that the Extension method isn't literally a part of the interface itself - it's still a static method "under the hood," it's just that the compiler's allowing you the convenience of treating this like an instance method.

Assuming
public class RequestYoyoEnvelope : IRequestYoyoEnvelope { ... }
Your extension method would need to target the interface
public static ResponseYoyoEnvelope ToResponseYoyoEnvelope(this IRequestYoyoEnvelope target) { ... }
Keep the action as is because the model binder will have issues binding the interface.
In your unit test you pass a concrete implementation of RequestYoyoEnvelope and the updated extension method should be able to be tested.
From your example you would not need an interface to test if that method is the method under test. just new up an instance of the model and pass it to the method during the unit test.
[TestMethod]
public void GetAccountsByYoyoIdTest() {
//Arrange
var controller = new YoyoController();
var yoyoId = 123456;
var model = new RequestYoyoEnvelope {
//you populate properties for test
};
//Act
var result = controller.GetAccountsByYoyoId(model, yoyoId);
//Assert
//...do your assertions.
}

Related

How to mock classes with internal constructors and static factory method?

I have class MyService that depends on ABCService (Nuget package/sdk)
public class MyService
{
private readonly ABCService _abc;
public MyService(ABCService abc)
{
this._abc = abc;
}
public async Task Run(string id)
{
// some logic
var result = await this._abc.DoSomething(id);
// some logic
}
}
ABCService looks something like this:
public class ABCService
{
internal ABCService(string someConnectionString, object someSettings)
{
// ... initialization
}
public static CreateFromConnectionString(string someConnectionString, object someSettings)
{
// some logic
return new ABCService(someConnectionString, someSettings);
}
}
Mocking class this way would not work and throws exception. "Parent does not have a default constructor."
var mock = new Mock<ABCService>();
var myService = new MyService(mock.Object);
How should I approach this? Is there a way to mock such classes?
The only thing that comes to my mind is creating interface IABCService and then injecting it in the constructor of MyService
public class IABCService
{
Task DoSomething(string id);
}
public class MyService
{
private readonly IABCService _abc;
public MyService(IABCService abc)
{
this._abc = abc;
}
}
And then I could do this:
var mock = new Mock<IABCService>();
var myService = new MyService(mock.Object);
Popular isolation frameworks such as Moq, NSubstitute or FakeItEasy are constrained. They can substitute only virtual methods. To use them, you will have to use the interface, as you already guessed. This is the recommended way to easily maintain loose coupling and testability.
There are bunch of unconstrained mocking frameworks: TypeMock Isolator, JustMock, Microsoft Fakes (all three are paid) and free open source Prig, Pose, Shimmy, Harmony, AutoFake, Ionad.Fody, MethodRedirect. They allow to mock non-virtual members, including private, static, etc.
Some of them allow you to work wonders, but you should not get too carried away with using them, because in the end it can lead to bad architecture.

Moq CallBase on mock of interface

Let's assume we have the following setup:
public interface IBase
{
void Foo();
}
public class Base : IBase
{
public virtual void Foo()
{
Console.WriteLine("Called Base.Foo()");
}
}
public interface IChild : IBase
{
void Bar();
}
public class Child : Base, IChild
{
public virtual void Bar()
{
Console.WriteLine("Called Child.Bar()");
}
}
When mocking the Child object everything works fine:
var child = new Mock<Child> { CallBase = true };
child.Object.Bar();
child.Object.Foo();
Output is:
Called Child.Bar()
Called Base.Foo()
But when mocking the IChild interface nothing is printed to the console:
var child = new Mock<IChild> { CallBase = true };
child.Object.Bar();
child.Object.Foo();
Let's assume I can't mock the Child object because there is no parameterless constructor (dependency injection).
I know that I could just do the following:
child.Setup(c => c.Bar()).Callback(() =>
{
// Copy paste bar-method body
});
child.Setup(c => c.Foo()).Callback(() =>
{
// Copy paste foo-method body
});
But that would be very ugly.
Is there a clean solution using Mock<IChild>?
As long as you are mocking the interface, you have no access or information about the real classes which explains why you don't get any output (but I guess you understood that).
Unfortunately if you choose to mock an interface (which by definition have no behavior), the only way to make things happen is to Setup the method the way you did.
Another "dirty" way would be to use method extension to your child and base class if the content of the method is only using public attributes and method.
public static class ChildExtension
{
public static void Bar(this Child child)
{
Console.WriteLine("Called Child.Bar()");
}
}
You are going to the wrong direction
Mock exists to help in unit testing. For example if you want to test the method Save() of a class which uses a wrapper over a DbContext like the following:
interface IRepository
{
void PersistData(object dataToBeSaved);
}
class DataSaver
{
private IRepository _repository;//this object's method PersistData makes a call to a database
public DataSaver(IRepository repository)
{
_repository = repository;
}
public void Save(object dataToBeSaved)
{
_repository.PersistData(dataToBeSaved);
}
}
In this case, in order to test the method Save of the DataSaver you will do a call to it in a unit test, but the problem you will face when doing this is that the method will actually try to save the data using the repository objet. Unless you send a fake repository your unit test will save data every time you run it, and this is not what a unit test should be doing. It should not run a method from a concrete IRepository object, but it should still call it's method.
What you could do in this case to avoid saving of an object is to make another class which implements IRepository only for testing:
class DummyRepository : IRepository
{
public object DataJustSaved { get; set; }
public void PersistData(object dataToBeSaved)
{
DataJustSaved = dataToBeSaved;
}
}
Now in your unit test you will do something like this:
var dummyRepository = new DummyRepository();
var dataSaver = new DataSaver(dummyRepository);
var savedObject = new Object();
var expectedObject = savedObject;
dataSaver.Save(savedObject);//test the save method
var actualObject = dummyRepository.DataJustSaved;
Assert.AreEqual(expectedObject, actualObject);//verify that the data was passed to the PersistData method
Here the Mock helps
It would be quite difficult to make a fake class for each unit test, that is what alternative mock offers:
var dummyRepository = new Mock<IRepository>();
var dataSaver = new DataSaver(dummyRepository.Object);
var savedObject = new Object();
dataSaver.Verify(x => x.PersistData(savedObject), Times.Once());// just make sure the method PersistData was invoked with the expected data and only once.
The reason Mock exists is to make pretty smart dummies for you, to write unit tests without a great impact but which can reveal bugs, and keep the code doing what only it's supposed to do.
In your case, if you really want to call the actual method of the concrete object:
child.Setup(c => c.Bar()).Callback(() =>
{
Console.WriteLine("Called Child.Bar()");
});
Then it means that you should not even try to use the mock to reproduce the exact same implementation of the object you mock. What would be the use of the mock if it is doing the same thing as the actual object?
In this case you should remove the mock and create a concrete Child object, as you do not want to simulate the behavior of a child, you are trying to achieve it using a mock which removes the functionality of the mock itself.
The simple answer is to use the concrete object in the unit test:
var child = new Child();
child.Bar();
child.Foo();

Unit testing using Mock in MVC

I am trying to implement an unit test for a method in my class. How could I mock a base class indexer on the class method I am testing? Below code snippet should give a clear picture of my requirement.
public class MyClass:MyBase
{
public string returnString(string str1)
{
var xyz=base[str1];
//My code to unit test is here
}
}
public class MyBase
{
public virtual string this[string str1]
{
return "prefix"+str1;
}
}
I would like to stub my base class indexer with a dummy string and test my actual code. How can I do that?
Thanks for any help on this in advance.
Sree.
Normally not recommended practice, but in this case "appropriate": mock your class under test. Of course in this case, you'd only mock out stuff that's specific to the base class and not overridden in any way your descendant under test. This ensures that the base class' behavior is mocked and therefore under control of the tests when testing the descendant's methods.
In your example, you would create a mock of MyClass but only mock out the inherited (MyBase's) constructor, thus making sure that all other methods run "as coded", and then assert against the mocked instance.
I don't see the reason to stub your base class, since you can mock your class under test. I'll show you.
I added return statement to returnString() method, just for assertion to complete the test:
public string returnString (string str1)
{
var xyz = base [str1];
return xyz;
}
And now the test:
[TestMethod, Isolated]
public void TestIndexerFake()
{
//Arrange
var MyClassFake = Isolate.Fake.AllInstances<MyClass>(Members.CallOriginal);
Isolate.WhenCalled(() => MyClassFake["test"]).WillReturn("fake!");
//Act
MyClass target = new MyClass();
var result = target.returnString("test");
//Assert
Assert.AreEqual("fake!", result);
}
I'm using Typemock Isolator and MsTest.
Hope it helps!

How to unit test delegate was received in base class method?

I currently have a base service class that all my services extend. This is what one of the methods look like:
protected internal virtual T PerformServiceOperationWithExceptionHandling<T>(Func<T> func)
{
try
{
return func.Invoke();
}
...
}
In the derived classes I call the method like this:
public AddGuestResponse AddGuest(AddGuestRequest addGuestRequest)
{
return PerformServiceOperationWithExceptionHandling(() => AddGuestLogic(addGuestRequest));
}
I want to test AddGuest and ensure "AddGuestLogic" is being passed as a parameter in the base method? How do I achieve this with nSubstitute and nUnit. I don't think its possible?
================================================
I ended up using the following code:
[Test]
public void AddGuest_WhenCalled_PerformsAddGuestLogicWithExceptionHandling()
{
Func<AddGuestResponse> addGuestLogic = null;
_guestService.PerformServiceOperationWithExceptionHandling(Arg.Do<Func<AddGuestResponse>>(arg => addGuestLogic = arg));
var addGuestRequest = new AddGuestRequest();
_guestService.AddGuest(addGuestRequest);
_guestService.ClearReceivedCalls();
addGuestLogic.Invoke();
_guestService.Received().AddGuestLogic(addGuestRequest);
}
The _guestService is created in my setup method as follows: Substitute.ForPartsOf();
I second Sunny Milenov's answer, but would go one step further by advising you to change your design. I have learned the hard way that many of these headaches with testing base class behavior go away when you follow the principle of composition over inheritance.
I.e., if you refactor your base class to a collaborator, which you inject into your services' constructor, you can test that in isolation and mock it in your services' tests. No worrying about testing an abstract base class or testing the same exception handling in all of your services' tests.
You would test that the collaborator correctly invokes the func in the collaborator's tests.
In the services' tests you can just mock the collaborator to return the Func's result right away:
[Test]
public void ServiceLogicIsExecuted()
{
var collaborator = Substitute.For<ICollaborator>();
//Tell the test double to return the Func's result. You'd probably want to do this in the setup method.
collaborator.PerformServiceOperation(Arg.Any<Func<int>>()).Returns(x => ((Func<int>)x[0]).Invoke());
var sut = new Service(collaborator);
var result = sut.CalculateSomething();
Assert.That(result, Is.EqualTo(99));
}
public class Service
{
private readonly ICollaborator _collaborator;
public Service(ICollaborator collaborator)
{
_collaborator = collaborator;
}
public int CalculateSomething()
{
return _collaborator.PerformServiceOperation(ExecuteLogic);
}
private static int ExecuteLogic()
{
return 99;
}
}
public interface ICollaborator
{
T PerformServiceOperation<T>(Func<T> func);
}
Short answer - you shouldn't. Unit testing is about testing the behavior of the tested method, not the implementation details.
Long answer:
It doesn't matter how the class internally works, as far as it produces the expected results.
You need to test your public method on the final class and see if this works as expected. Testing a base/abstract class in isolation proves nothing.

Does the methods in mocked objects work?

Does the methods in mocked objects work ?
For example if I have an object with method name Method1 and I mock the object :
var mockobject= Mock<myobject>();
Does the next call to method work :
mockobject.Method1()
?
It is a question to clarify about the mock objects.
If you're mocking a concrete class or abstract class with method implementations. For virtual methods you have two options.
Create a Setup to fake the method call
mockobject.Setup(x => x.Method1()).Returns(true);
Set CallBase = true on the mock to invoke the concrete behavior of the Method1 method.
mockobject.CallBase = true;
Usage:
public class MyClass
{
public virtual int MyMethod()
{
return 5;
}
}
[Test]
public void ShouldGiveMeZero()
{
var mockMyClass = new Mock<MyClass>();
// returns default(int)
Assert.AreEqual(0, mockMyClass.Object.MyMethod());
}
[Test]
public void ShouldGiveMeFive()
{
var mockMyClass = new Mock<MyClass>();
mockMyClass.CallBase = true;
// calls concrete implementation
Assert.AreEqual(5, mockMyClass.Object.MyMethod());
}
[Test]
public void ShouldGiveMeSix()
{
var mockMyClass = new Mock<MyClass>();
mockMyClass.Setup(x => x.MyMethod()).Returns(6);
// calls Setup
Assert.AreEqual(6, mockMyClass.Object.MyMethod());
}
First, note that your example will never compile:
mockobject.Method1()
Method1 doesn't live on the mock object itself--it lives in the underlying mocked object instance:
mockobject.Object.Method1();
The behavior of that call depends on what MockBehavior you're using (Strict or Loose). It also depends on if the method you're calling is marked virtual or not.
If Method1 is non-virtual, the implementation for the actual type will be used, since Mock cannot mock non-virtual methods.
For example, if MyObject is defined like this:
public class MyObject
{
public int Method1()
{
return 1;
}
}
mockObject.Object.Method1() will return 1 since Mock is unable to provide any other implementation for the method.
Now, if Method1 is declared virtual:
public virtual int Method1()
{
return 1;
}
The MockBehavior comes into play. The default is MockBehavior.Loose, which means that methods not defined using the .Setup method will return default(T) where T is the return type of the method. So the following:
var mockObject = new Mock<MyObject>(MockBehavior.Default);
int result = mockObject.Object.Method1();
Will always return 0 unless you use .Setup to make it return otherwise. You can also specify CallBase = true on the Mock<MyObject> instance and the base implementation will be invoked for methods that aren't defined using .Setup.
If you're using MockBehavior.Strict, unimplemented methods will throw an exception:
var mockObject = new Mock<MyObject>(MockBehavior.Strict);
int result = mockObject.Object.Method1(); // Always throws an exception
If you look at the quickstart guide there are simple examples to get you going, e.g.
var mock = new Mock<IFoo>();
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);
Note the call to Setup to make the mock/fake actually do something.
In this situation you have created the default stub for Method1. If you were to create this by hand you would have code similar to:
public class MyObject {
public virtual void Method1() {
throw new NotImplementedException();
}
}
Your stub would be:
public class Stub : MyObject {
public override void Method1() {
}
}
So now instead of getting a NotImplementedException you have an instance of MyObject that will allow you to call Method1 regardless of its original implementation.
Note my usage of virtual. Without the usage of virtual there is nothing for Moq to override.
This is actually one of my favorite usages of mocking. Many people go overboard with interfaces for everything "for mocking". The most baseline scenarios only require methods to be virtual. In general I mark nearly every public method I create as virtual. If a public method cannot be virtual, it is likely a violation of the Open Closed Principle.

Categories

Resources