Mocking a Fluent interface using Moq - c#

I have looked at a number of questions here on this subject but none seem to address the issue I'm having.
I've got code that looks a bit like this...
IBaseDataCollector<MyClass> myDataCollector;
myDataCollector = new Mock<IBaseDataCollector<MyClass>>();
systemUnderTest = new Thing(myDataCollector.Object);
And in my Thing class...
var collection = myDataCollector.SomeMethod()
.SomeSecondMethod()
.GetData();
where both SomeMethod() and SomeSecondMethod() return this (ie the instance of myDataCollector)
When I run my test I get a NullReferenceException on the like where I call myDataCollector.
I tried adding this in my test setup...
myDataCollector.Setup(_=> _.SomeMethod()),Returns(myDataCollector.Object);
but that wouldn't even compile, complaining that it "Could not resolve method 'Returns(IBaseDataCollector)'"
Now, if I refactor my Thing class to read...
myDataCollector.SomeMethod();
myDataCollector.SomeSecondMethod()
var collection = myDataCollector.GetData();
my test executes properly.
If this was it, I'd just refactor my code and get on with life, but, in reality, I need to call my code inside a SelectMany call...
var collection = list.SelectMany(_=> myDataCollector.SomeMethod()
.SomeSecondMethod(_)
.GetData());
Again, I know I could replace the SelectMany with, say, a ForEach and manually populate the collection with the results of each iteration of the call to GetData() so that I can get rid of the fluent element of the calls, but this means refactoring the code just to make the tests work, which feels wrong.
How should I be calling Setup() on my Mocked objects to make my fluent calls work?

Take a look at the following test code (I've invented some details to fill in the blanks). The mocked object instance should be available as a value to return from its own methods as shown.
public class UnitTestExample
{
[Fact]
public void UnitTestExample1()
{
var myClassInterfaceMock = new Mock<IInterface<MyClass>>();
var instance = myClassInterfaceMock.Object;
var myList = new List<MyClass>()
{
new MyClass() { Attribute = 1 }
};
myClassInterfaceMock.Setup(_ => _.SomeMethod()).Returns(instance);
myClassInterfaceMock.Setup(_ => _.SomeSecondMethod()).Returns(instance);
myClassInterfaceMock.Setup(_ => _.GetData()).Returns(myList);
var myDependentClass = new MyDependentClass(instance);
var result = myDependentClass.DoTheThing();
Assert.True(result.Count.Equals(1));
}
}
public interface IInterface<T>
{
IInterface<T> SomeMethod();
IInterface<T> SomeSecondMethod();
List<T> GetData();
}
public class MyClass
{
public int Attribute { get; set; }
}
public class MyDependentClass
{
private readonly IInterface<MyClass> _test;
public MyDependentClass(IInterface<MyClass> test)
{
_test = test;
}
public List<MyClass> DoTheThing()
{
return _test.SomeMethod().SomeSecondMethod().GetData();
}
}

Related

Fake extension method using exact arguments

I am writing tests for our C# 7 application and struggle with mocking an Extension method. I am using TypeMock 8.6.10.3.
Here is a simplified example:
internal class InnerClass
{
private readonly string _description;
public InnerClass(string description)
{
_description = description;
}
public string GetDescription()
{
return _description;
}
}
internal class OuterClass
{
public void DoSthWithExtension(int someNumber)
{
var innerClass = new InnerClass("InnerClassDescription");
innerClass.Extension(someNumber);
}
}
internal static class Extensions
{
public static void Extension(this InnerClass innerClass, int someNumber)
{
var d = innerClass.GetDescription();
}
}
public void TestExtension()
{
// I want to fake the method "InnerClass.Extension()"
// which is called by "OuterClass.DoSthWithExtension()".
// I don't have access to the InnerClass instance though.
// So unfortunately I have to fake them all.
var fakedInnerClasses = Isolate.Fake.AllInstances<InnerClass>();
Isolate.WhenCalled(() => Extensions.Extension(fakedInnerClasses, 11)).WithExactArguments().DoInstead(
c =>
{
// The test doesn't go in here. The second parameter is correct,
// the first one obviously not. But what is expected as a first parameter then?
var oc2 = new OuterClass();
// Here I call InnerClass.Extension() again.
// The test should now go into the faked method underneath.
oc2.DoSthWithExtension(22);
});
Isolate.WhenCalled(() => Extensions.Extension(fakedInnerClasses, 22)).WithExactArguments().DoInstead(
c =>
{
// As above, the test code doesn't go in here.
});
// In here an instance of InnerClass is created and
// InnerClass.Extension(11) is called.
var oc1 = new OuterClass();
oc1.DoSthWithExtension(11);
}
As the this parameter of the Extension method I choose the faked instances of InnerClass. Thats what I assume is needed. But TypeMock does not bring me into the faked method. Obviously its the wrong parameter. But which one should I choose then?
Based on comments and updated question, the part that is confusing is why the other outer class is needed. The shown inner class has no dependency on the outer. Why would the mock then need to create a new outer class?
That aside, based on the docs its appears that you need to setup the extension class so that you can fake the static extension calls.
Isolate.Fake.StaticMethods(typeof(Extensions));
//...
Original answer
Do not fake the extension method in this case. You know what the extension method calls. so fake that.
public void TestExtension() {
//Arrange
string expected = "Fake result";
var fakedInnerClasses = Isolate.Fake.AllInstances<InnerClass>();
Isolate.WhenCalled(() => fakedInnerClasses.GetDescription())
.WillReturn(expected);
var subject = new OuterClass();
//Act
subject.DoSthWithExtension();
//Assert
//...
}
So now when the outer is called and the extension method invoked, it will be acting on the mock controlled by you.

Unit test a void method with Mock?

I want to test a void method with Mock.
public class ConsoleTargetBuilder : ITargetBuilder
{
private const string CONSOLE_WITH_STACK_TRACE = "consoleWithStackTrace";
private const string CONSOLE_WITHOUT_STACK_TRACE = "consoleWithoutStackTrace";
private LoggerModel _loggerModel;
private LoggingConfiguration _nLogLoggingConfiguration;
public ConsoleTargetBuilder(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration)
{
_loggerModel = loggerModel;
_nLogLoggingConfiguration = nLogLoggingConfiguration;
}
public void AddNLogConfigurationTypeTagret()
{
var consoleTargetWithStackTrace = new ConsoleTarget();
consoleTargetWithStackTrace.Name = CONSOLE_WITH_STACK_TRACE;
consoleTargetWithStackTrace.Layout = _loggerModel.layout + "|${stacktrace}";
_nLogLoggingConfiguration.AddTarget(CONSOLE_WITH_STACK_TRACE, consoleTargetWithStackTrace);
var consoleTargetWithoutStackTrace = new ConsoleTarget();
consoleTargetWithoutStackTrace.Name = CONSOLE_WITHOUT_STACK_TRACE;
consoleTargetWithoutStackTrace.Layout = _loggerModel.layout;
_nLogLoggingConfiguration.AddTarget(CONSOLE_WITHOUT_STACK_TRACE, consoleTargetWithoutStackTrace);
}
The thing is I am not sure how to test it. I have my primary code.
public class ConsoleTargetBuilderUnitTests
{
public static IEnumerable<object[]> ConsoleTargetBuilderTestData
{
get
{
return new[]
{
new object[]
{
new LoggerModel(),
new LoggingConfiguration(),
2
}
};
}
}
[Theory]
[MemberData("ConsoleTargetBuilderTestData")]
public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
{
// ARRANGE
var targetBuilderMock = new Mock<ITargetBuilder>();
targetBuilderMock.Setup(x => x.AddNLogConfigurationTypeTagret()).Verifiable();
// ACT
var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
// ASSERT
Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}
Please guide me to the right direction.
It looks to me like you don't need a mock at all. You are testing AddNLogConfigurationTypeTagret. Not the constructor.
[Theory]
[MemberData("ConsoleTargetBuilderTestData")]
public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
{
// ARRANGE
var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
// ACT
consoleTargetBuilder.AddNLogConfigurationTypeTagret();
// ASSERT
Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}
If you don't want to call AddNLogConfigurationTypeTagret yourself, it should be called in the constructor. This changes the test to this :
[Theory]
[MemberData("ConsoleTargetBuilderTestData")]
public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
{
// ARRANGE
// ACT
var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
// ASSERT
Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}
and the class constructor should then be :
public ConsoleTargetBuilder(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration)
{
_loggerModel = loggerModel;
_nLogLoggingConfiguration = nLogLoggingConfiguration;
AddNLogConfigurationTypeTagret();
}
Please guide me to the right direction, I want two things. A) the method was called. B) two targets were added. So the expected count is 2.
A) If you wish to verify that method AddNLogConfigurationTypeTagret was called, then you need to test it on the code which is calling this method. E.g. something like the class ConsoleTargetBuilderClient which is an hypothetical example of a class which is using the ITargetBuilder (in your own code you should have some place where the class ConsoleTargetBuilder is used).
public class ConsoleTargetBuilderClient
{
private ITargetBuilder _builder;
public ConsoleTargetBuilderClient(ITargetBuilder builder)
{
_builder = builder;
}
public void DoSomething()
{
_builder.AddNLogConfigurationTypeTagret();
}
}
Then you can have a test which verifies that the method DoSomething called the method AddNLogConfigurationTypeTagret. For that purpose you can use a mock of ConsoleTargetBuilder because you test interaction with it. Test might look like this:
public void DoSomething_WhenCalled_AddNLogConfigurationTypeTagretGetsCalled()
{
// Arrange
bool addNLogConfigurationTypeTagretWasCalled = false;
Mock<ITargetBuilder> targetBuilderMock = new Mock<ITargetBuilder>();
targetBuilderMock.Setup(b => b.AddNLogConfigurationTypeTagret())
.Callback(() => addNLogConfigurationTypeTagretWasCalled = true);
ConsoleTargetBuilderClient client = new ConsoleTargetBuilderClient(targetBuilderMock.Object);
// Act
client.DoSomething();
// Assert
Assert.IsTrue(addNLogConfigurationTypeTagretWasCalled);
}
B) If you wish to verify that the targets were added you need to test the code itself (not mock of it). Test might look like this:
public void AddNLogConfigurationTypeTagret_WhenCalled_ConsoleTargetsAdded()
{
// Arrange
const int expectedConsoleTargetCount = 2;
var loggerModel = new LoggerModel();
var nLogLoggingConfiguration = new LoggingConfiguration();
var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
// Act
consoleTargetBuilder.AddNLogConfigurationTypeTagret();
// Assert
Assert.AreEqual<int>(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}
Note: google value-based vs. state-based vs. interaction testing.
Generally speaking, you shouldn't be mocking the class you want to test, you should be mocking it's dependencies. When you start mocking the class you're trying to test things often get entwined leading to brittle tests and it's difficult to determine if you're testing your code, or you mocking setup, or both.
The method AddNLogConfigurationTypeTagret is a public method on the class you're testing, so as #Philip has said, you should probably just be calling it from your test, or it should be called from your constructor. If you goal is for it to be called from your constructor, then I'd suggest that it should probably be a private method unless there's a reason for it to be called from outside the class.
As far as testing the effects of a void method call, you're interested in the state change caused by the method. In this instance, whether or not the _nLoggingConfiguration has two targets added with the correct attributes. You don't show us the nLoggingConfiguration.AllTargets property, but I would assume from the fact that you're using the Count property in your test, that you could simply inspect the items in the list to confirm that the correct name and layout have been added to the correct target type.
// Assert
targetBuilderMock.Verify(x => x.AddNLogConfigurationTypeTagret(), Times.Once());

How do you retrieve results from a service layer/repository with Moq?

I have a little bit of a problem with Moq. I have created a fake repository with a fake service class so I can show you where I am getting the problem.
If you see below I have only got an Add() and GetAllStrings() method in my repository, which are used in the FakeService class to do the AddFakeThings() and GetallTheFakeThings(). The problem is, when I add strings inside my repository using the service class, the list of the service class doesn't increment, so I will never be able to test if the items are added inside.
Why is that?
I have seen solutions where people create fake repositories with the data inside, but that is too messy to test an enterprise solution, is there any other way?
//## Interface for Fake Repository
public interface IFakeRepo
{
void Add(string something);
IList<string> GetAllStrings();
}
//## Fake Repository
public class FakeRepo:IFakeRepo
{
private List<string> mylist;
public FakeRepo()
{
mylist = new List<string>();
}
public void Add(string something)
{
mylist.Add(something);
}
public IList<string> GetAllStrings()
{
return mylist;
}
}
//## Interface for the Fake Service
public interface IFakeService
{
void AddAFakeThing(string thing);
IList<string> GetAllTheFakeThings();
}
//## Fake Service
public class FakeService: IFakeService
{
private IFakeRepo _fakerepo;
public FakeService(IFakeRepo fakerepo)
{
_fakerepo = fakerepo;
}
public void AddAFakeThing(string thing)
{
_fakerepo.Add(thing);
}
public IList<string> GetAllTheFakeThings()
{
return _fakerepo.GetAllStrings();
}
}
//## This is what I am testing... the result should be 3 or 1 as I am adding 3 strings to the Repo or 1 string with the service and they are null
[TestMethod]
public void Test_Fake_Class()
{
//## Creating my fake repo
var _mFakeRepo = new Mock<IFakeRepo>();
//## Init Fake Service
var service = new FakeService(_mFakeRepo.Object);
//## Adding strings
_mFakeRepo.Setup(x => x.Add("hello2"));
_mFakeRepo.Setup(x => x.Add("Bye2"));
_mFakeRepo.Setup(x => x.Add("hola2"));
service.AddAFakeThing("hahaha");
//## I suppose to get a result
//## BUT I AM NOT GETTING ANYTHING... WHERE IS THE DATA FROM THE REPO
var result = service.GetAllTheFakeThings();
//## This should work
Assert.IsTrue(result.Count == 3);
//## Or this...
Assert.IsTrue(result.Count == 1);
}
I don't see why you are using Moq? You implemented all the code yourself, and want to see that works as expected. Just use the code you wrote, without Moq.
Moq is a library to use when you don't have (or want to use) an actual implementation, and just want to see what methods are invoked and/or control what is returned by the methods so you can test the caller.
So in your case you would create a Mock of the Repo if you want to see that Add is called in a certain scenario, or want to test what happens if Add throws an exception.

Call private class method not being initialized in constructor

I am writing a unit test and one of the issues that I encounter is null exception on a private class that is not part of DI or not being initialized on constructor parameters. Anyone can help me? Here's my code. My problem is that how to mock PPortalSessionVariables class.
Controller:
public class EducatorController : BaseController
{
//Note: PPortalSessionVariables class should NOT be part of IOC
private readonly IPPortalSessionVariables _ppsessionVariable = new PPortalSessionVariables();
private readonly IEducatorService _educatorService;
public EducatorController(IEducatorService educatorService)
{
_educatorService = educatorService;
}
public ActionResult Index()
{
//during test null exception occurs on _ppsessionVariable.CurrentChild.Id
var model = _educatorService.GetEducatorsForChild(Convert.ToInt64(_ppsessionVariable.CurrentChild.Id));
return View(model);
}
}
Test Class:
[TestClass]
public class EducatorControllerTests
{
public EducatorController CreateController(Mock<IEducatorService> educatorService = null)
{
educatorService = educatorService ?? new Mock<IEducatorService>();
HttpContext.Current = HttpMockHelpers.FakeHttpContextCurrent();
var controller = new EducatorController(educatorService.Object);
controller.SetFakeControllerContext("?site=2");
return controller;
}
[TestMethod]
public void Index_Get_ReturnIndexView()
{
var ppsessionVariable = new Mock<IPPortalSessionVariables>();
var controller = CreateController();
var child = new ChildModel();
child.Id = 0;
ppsessionVariable.Setup(x => x.CurrentChild).Returns(child);
var result = controller.Index() as ViewResult;
Assert.IsNotNull(result);
}
}
There are two things that are really causing this headache for you:
The fact that _ppSessionVariable is private, and not exposed to the outside world
There is an assumption that IPPortalSessionVariables.CurrentChild should never return null, for all implementations of the interface
If you address either of these points, then your problem goes away.
Expose a public setter to allow the unit test to explicitly set the _ppsessionVariable to the mock object. Something like:
public void SetSessionVariable(IPPortalSessionVariables ppsessionVariable)
{
_ppsessionVariable = ppsessionVariable;
}
Refactor your code to prevent _ppsessionVariable.CurrentChild from returning null.
The simplest thing would probably be to initialize CurrentChild to a Null Object, in the PPortalSessionVariables constructor.
Your EducatorController is clearly very tightly coupled with PPortalSessionVariables. Till the time you have new PPortalSessionVariables() in the controller unit testing it in isolation will not be possible.
In order to fix this, make sure the EducatorController depends on an abstraction IPPortalSessionVariables instead of the concrete implementation.
Like others have already suggested, consider having a public setter for IPPortalSessionVariables or go ahead with a constructor injection.
Don't understand why you just don't use it as any other dependency injecting it via IoC. As far as Moq works you should mock that class but never will be able to set that object, maybe a workaround is create a setter for that property and call the property in your test passing the mock object.
EducatorController
public void SetPortalSession(IPPortalSessionVariables portal)
{
_ppsessionVariable = portal;
}
EducatorControllerTests
[TestMethod]
public void Index_Get_ReturnIndexView()
{
var ppsessionVariable = new Mock<IPPortalSessionVariables>();
var controller = CreateController();
controller.SetPortalSession(ppsessionVariable.object);
var child = new ChildModel();
child.Id = 0;
ppsessionVariable.Setup(x => x.CurrentChild).Returns(child);
var result = controller.Index() as ViewResult;
Assert.IsNotNull(result);
}

How can I assert that a particular method was called using NUnit?

How can I test that a particular method was called with the right parameters as a result of a test? I am using NUnit.
The method doesn't return anything. it just writes on a file. I am using a mock object for System.IO.File. So I want to test that the function was called or not.
More context is needed. So I'll put one here adding Moq to the mix:
pubilc class Calc {
public int DoubleIt(string a) {
return ToInt(a)*2;
}
public virtual int ToInt(string s) {
return int.Parse(s);
}
}
// The test:
var mock = new Mock<Calc>();
string parameterPassed = null;
mock.Setup(c => x.ToInt(It.Is.Any<int>())).Returns(3).Callback(s => parameterPassed = s);
mock.Object.DoubleIt("3");
Assert.AreEqual("3", parameterPassed);
You have to use some mocking framework, such as Typemock or Rhino Mocks, or NMocks2.
NUnit also has a Nunit.Mock, but it is not well-known.
The syntax for moq can be found here:
var mock = new Mock<ILoveThisFramework>();
// WOW! No record/reply weirdness?! :)
mock.Setup(framework => framework.DownloadExists("2.0.0.0"))
.Returns(true)
.AtMostOnce();
// Hand mock.Object as a collaborator and exercise it,
// like calling methods on it...
ILoveThisFramework lovable = mock.Object;
bool download = lovable.DownloadExists("2.0.0.0");
// Verify that the given method was indeed called with the expected value
mock.Verify(framework => framework.DownloadExists("2.0.0.0"));
Also, note that you can only mock interface, so if your object from System.IO.File doesn't have an interface, then probably you can't do. You have to wrap your call to System.IO.File inside your own custom class for the job.
By using a mock for an interface.
Say you have your class ImplClass which uses the interface Finder and you want to make sure the Search function gets called with the argument "hello";
so we have:
public interface Finder
{
public string Search(string arg);
}
and
public class ImplClass
{
public ImplClass(Finder finder)
{
...
}
public void doStuff();
}
Then you can write a mock for your test code
private class FinderMock : Finder
{
public int numTimesCalled = 0;
string expected;
public FinderMock(string expected)
{
this.expected = expected;
}
public string Search(string arg)
{
numTimesCalled++;
Assert.AreEqual(expected, arg);
}
}
then the test code:
FinderMock mock = new FinderMock("hello");
ImplClass impl = new ImplClass(mock);
impl.doStuff();
Assert.AreEqual(1, mock.numTimesCalled);
In Rhino Mocks where is a method called AssertWasCalled
Here is a way to use it
var mailDeliveryManager = MockRepository.GenerateMock<IMailDeliveryManager>();
var mailHandler = new PlannedSending.Business.Handlers.MailHandler(mailDeliveryManager);
mailHandler.NotifyPrinting(User, Info);
mailDeliveryManager.AssertWasCalled(x => x.SendMailMessage(null, null, null), o => o.IgnoreArguments());

Categories

Resources