MOQ - How to verify static class call and delegates? - c#

I just started reading on Moq framework and thought of applying it to my existing code. I could come up with a test case to verify basic function calls. But now stuck at applying it to delegates and static classes.
Below is the system under test (SUT)
public class SUT : ISUT
{
private IInterface1 i1;,
private IInterface2 i2;
public SUT(IInterface1 i1, IInterface2 i2)
{
this.i1 = i1;
this.i2 = i2;
}
public void FunctionToTest(Action<string> someDelegate, Action otherDelegate)
{
var list = i2.GetList();
foreach(var r in list)
{
i1.SomeFunction(r);
if(someDelegate != null)
someDelegate("message");
SomeHelper.LogData(r);
}
if(otherDelegate != null)
otherDelegate();
}
}
I have setup my test as below
[TestFixture]
public class when_list_contains_atleast_one_item
{
ISUT sut;
Mock<IInterface1> mockI1;
Mock<IInterface2> mockI2;
public SUT_Tester()
{
mockI1 = new Mock<IInterface1>();
mockI2 = new Mock<IInterface2>();
sut = new SUT(mockI1.Object, mockI2.Object);
}
[Test]
public void it_should_call_somefunction_calldelegates_and_log_data()
{
var dummyList = new List<string> { "string1", "string2" };
mockI2.Setup(m2 => m2.GetList()).Returns(dummyList).Verifiable();
sut.FunctionToTest(It.IsAny<Action<string>>(), It.IsAny<Action>());
// How to verify delegates were raised
// How to verify SomeHelper.LogData was called
mockI1.Verify(m => m.SomeFunction(It.IsAny<string>()), Times.Exactly(2));
mockI2.Verify();
}
}
How to verify that someDelegate and otherDelegate were raised ?
SomeHelper is a static class and LogData is a static function. How to verify that LogData was called?
Below is the SomeHelper class
public static class SomeHelper
{
static ILogger logger = LoggerManager.GetLogger("Something");
public static void LogData(string input)
{
logger.Info(input);
}
}

You cannot verify static methods since they cannot be mocked by Moq.
In order to verify calls on the delegates, create them so that they call a local function and you keep the state and verify:
string localString = string.Empty;
Action<string> action = (string s) => localString = s;
// ... pass it to the test
Assert.(localString == "TheStringItMustbe");
(UPDATE)
OK to check an action that has no in params, increment a local variable and assert if it has been incremented (or something similar):
int localVar = 0;
Action action = () => localVar++;
// ... pass it to the test
Assert.(localVar == 1);

You might want to consider changing the IInterface1/2 interfaces so that they either take an ILogger as a parameter into SomeFunction, or have a settable ILogger property.
Then you could pass a mocked ILogger into SomeFunction.

Related

How can I determine if a function wrapped in an if statement gets called?

I have a class, like this one:
public class SomeClass: ISomeClass
{
public async Task<ServiceResponse> PerformAction(Context context)
{
if(IsPartner(context))
{
SendTextMessageAsync(context);
}
}
public bool IsPartner(Context context)
{
return SomeStaticHelperClass.GetIsPartner(context.PartnerId);
}
public async void SendTextMessageAsync(Context context)
{
// sends the message
}
}
ISomeClass exposes all three methods.
I'm using Moq and I would like to write a test that verifies
when IsPartner returns true
then SendTextMessage is called once.
I've tried everything I can think of.
This is my latest attempt:
public class ReceiptServiceTests
{
[Fact]
public async void SendReceiptsProofsNeededNudgeAsync_ShouldCallSendTextMessageAsync_WhenSessionPartnerIdIsNotNullOrEmptyString()
{
var context = new Context { PartnerId = "12345" };
var mockSomeClass = new Mock<ISomeClass>();
// force IsPartner to return true
mockSomeClass.Setup(m => m.IsPartner(context)).Returns(true);
// call PerformAction which should call SendTextMessageAsync
// because IsPartner will return true
await mockSomeClass.Object.PerformAction(context);
// verify SendTextMessageAsync was actually called
mockSomeClass.Verify(m => m.SendTextMessageAsync(It.IsAny<Context>()), Times.AtLeastOnce);
}
}
I keep getting following error:
(Expected invocation on the mock at least once, but was never performed: m => m.SendTextMessageAsync)
which i'm guessing is because SendTextMessageAsync is never called. I'm stuck here though, I don't understand how to properly call it.
I know some (or a lot) of this code doesn't make sense, I've changed it for brevity.
What I'm really just trying to figure out is how can I determine if a function (SendTextMessageAsync) is called when it is wrapped in an if statement that calls another function that returns true.
As rgvlee as already pointed out you can only mock dependencies and verify their method calls.
In your case SomeStaticHelperClass is your dependency and its GetIsPartner method that could be verified.
Unfortunately static classes are not good candidates for mocking. If you could replace that static class reference to an interface then you would be able to mock that easily.
SomeClass uses IPartnerService
public class SomeClass: ISomeClass
{
private readonly IPartnerService partnerSvc;
public SomeClass(IPartnerService partnerSvc)
{
this.partnerSvc = partnerSvc;
}
public async Task<ServiceResponse> PerformAction(Context context)
{
if(IsPartner(context))
{
SendTextMessageAsync(context);
}
}
public bool IsPartner(Context context)
{
return partnerSvc.GetIsPartner(context.PartnerId);
}
public async void SendTextMessageAsync(Context context)
{
// sends the message
}
}
SomeClass is using a IPartnerService mock during unit testing
public class ReceiptServiceTests
{
[Fact]
public async Task GivenAPartner_WhenICallPerformAction_ThenItCallsPartnerService()
{
//Arrange
const string partnerId = "12345";
var context = new Context { PartnerId = partnerId };
var partnerSvcMock = new Mock<IPartnerService>();
partnerSvcMock
.Setup(svc => svc.GetIsPartner(partnerId))
.Returns(true);
var SUT = new SomeClass(partnerSvcMock);
//Act
_ = await SUT.PerformAction(context);
//Assert
partnerSvcMock.Verify(svc => svc.GetIsPartner(partnerId), Times.Once);
}
}

How to mock the raising of a delegate on an interface that only has a setter?

I'm trying to mock an interface using Moq, but I can't see how to do it. The interface looks something like this:
public delegate void MyDelegate(int i);
public interface MyInterface
{
void Method(int i);
MyDelegate MyDelegate { set; }
}
I am testing a component that takes an object with this interface as a dependency. I would like to be able to test an interaction where the delegate is raised when the method is called, but I can't see how to do it. I know this is a slightly strange way to design an interface, but I don't have control over that.
Suppose I have a class like this to test:
class SystemUnderTest
{
int i = 0;
readonly MyInterface myInterface;
public SystemUnderTest(MyInterface myInterface)
{
this.myInterface = myInterface;
this.myInterface.MyDelegate = DelegateHandler;
}
public int Run(int input)
{
this.myInterface.Method(input);
return i;
}
void DelegateHandler(int i)
{
this.i = i;
}
}
I've tried a test like this, but it gives an exception when setting up the mock. "ArgumentException: Could not locate event for attach or detach method Void set_MyDelegate(ConsoleApp1.MyDelegate)."
static void Main(string[] args)
{
// Arrange
Mock<MyInterface> mock = new Mock<MyInterface>();
mock
.Setup(m => m.Method(It.IsAny<int>()))
.Raises(m => m.MyDelegate = null, 5);
// Act
var sut = new SystemUnderTest(mock.Object);
var result = sut.Run(5);
// Assert
Trace.Assert(result == 5);
}
You could so to say bridge your SystemUnderTest.DelegateHandler through a MyDelegate local variable. Try something like this:
MyDelegate del = null;
var mock = new Mock<MyInterface>();
mock.SetupSet(m => m.MyDelegate = It.IsAny<MyDelegate>())
.Callback<MyDelegate>(d => del = d);
mock.Setup(m => m.Method(It.IsAny<int>()))
.Callback<int>(i => del.Invoke(i));
Then actually your SystemUnderTest.DelegateHandler method will be called every time you invoke mock.Method.
I think the fundamental flaw in your approach is you're trying to mock something that doesn't actually occur in your code - namely that calling the void Method(int i) subsequently calls your delegate. You can't use Raises as that's for events.
I think you need a "stub" implementation of MyInterface, and you don't need to use Moq at all. Here's my code that passes the assertion:
using System.Diagnostics;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
// Arrange
var stub = new StubOfMyInterface();
// Act
var sut = new SystemUnderTest(stub);
var result = sut.Run(5);
// Assert
Trace.Assert(result == 5);
}
}
public delegate void MyDelegate(int i);
public interface MyInterface
{
void Method(int i);
MyDelegate MyDelegate { set; }
}
public class StubOfMyInterface : MyInterface
{
public void Method(int i)
{
MyDelegate?.Invoke(i);
}
public MyDelegate MyDelegate { get; set; }
}
class SystemUnderTest
{
int i = 0;
readonly MyInterface myInterface;
public SystemUnderTest(MyInterface myInterface)
{
this.myInterface = myInterface;
this.myInterface.MyDelegate = DelegateHandler;
}
public int Run(int input)
{
this.myInterface.Method(input);
return i;
}
void DelegateHandler(int i)
{
this.i = i;
}
}
}

How to do the Assert phase of a private method whose return type is Void?

I have a class with a private method
public class MyClass
{
private void SomeMethod(PrimaryAllocationDP packet)
{
........................
some code
........................
packet.AllocatedAgency = AgencyAllocated;
}
}
Now by using MSUnit Testing framework, I have written so far
[TestMethod]
public void TestAllocatedAgency()
{
var packet = new Fixture().Create<PrimaryAllocationDP>(); //used AutoFixture here
PrivateObject accessor = new PrivateObject(new MyClass());
accessor.Invoke("SomeMethod", packet); //Act
// what will be the Assert? Since it is void
}
What will be the Assert? Since it is void, how can I write the assert?
Well given that in the example the method under test is making a change to its argument/dependency you could assert that the desired result of calling the function is that the packet's AllocatedAgency property is in fact not null
[TestMethod]
public void TestAllocatedAgency() {
//Arrange
var packet = new Fixture().Create<PrimaryAllocationDP>(); //used AutoFixture here
var sut = new MyClass();
var accessor = new PrivateObject(sut);
//Act
accessor.Invoke("SomeMethod", packet);
//Assert
Assert.IsNotNull(packet.AllocatedAgency);
}
If it is possible for you to change PrimaryAllocationDP you can also add a new interface IPrimaryAllocationDP and test the property setting. In my test I am assuming AllocatedAgency is of type object and I am using Moq. But maybe you can also use AutoFixture for mocking? To make it more clear I set AgencyAllocated directly in MyClass
[TestFixture]
public class DependencyInjection
{
[TestMethod]
public void TestAllocatedAgency()
{
var packet = new Mock<IPrimaryAllocationDP>();
PrivateObject accessor = new PrivateObject(new MyClass());
accessor.Invoke("SomeMethod", packet.Object); //Act
packet.VerifySet(p => p.AllocatedAgency = 42);
}
}
public interface IPrimaryAllocationDP
{
//object or any other type
object AllocatedAgency { set; }
}
public class PrimaryAllocationDP : IPrimaryAllocationDP
{
public object AllocatedAgency { set; private get; }
}
public class MyClass
{
private readonly object AgencyAllocated = 42;
private void SomeMethod(IPrimaryAllocationDP packet)
{
//........................
//some code
//........................
packet.AllocatedAgency = AgencyAllocated;
}
}

How do I mock a Func<> using Machine.Fakes (Moq)?

I'm trying to test some code I've written have run in to issues trying to mock a func using Machine.Fakes (which uses Moq under the hood). See the code below for an example.
public class RoutingEngine : IRoutingEngine
{
private readonly IMessageRouters _messageRouters;
public RoutingEngine(IMessageRouters messageRouters)
{
_messageRouters = messageRouters;
}
public void Route<T>(T inbound)
{
var messageRouters = _messageRouters.Where(x => x.CanRoute(inbound));
foreach(var router in messageRouters)
router.Route(inbound);
}
}
public class MessageRouters : IMessageRouters
{
public IList<IMessageRouter> _routers = new List<IMessageRouter>();
public IEnumerable<IMessageRouter> Where(Func<IMessageRouter, bool> func)
{
return _routers.Where(func);
}
public void Add(IMessageRouter messageRouter)
{
_routers.Add(messageRouter);
}
}
And the test is here
public class when_routing_a_message_with_fakes : WithSubject<RoutingEngine>
{
Establish that = () =>
{
Message = new MyMessage{ SomeValue= 1, SomeOtherValue = 11010 };
Router = The<IMessageRouter>();
Router.WhenToldTo(x => x.CanRoute(Message)).Return(true);
The<IMessageRouters>().WhenToldTo(x => x.Where(router => router.CanRoute(Message))).Return(new List<IMessageRouter> { Router });
};
Because of = () => Subject.Route(Message);
It should_do_route_the_message = () => Subject.WasToldTo(x => x.Route(Param.IsAny<MyMessage>()));
static MyMessage Message;
static IMessageRouter Router;
}
I get an unsupported expression for the above so I changed the where method on the IMessageRouters to the following:
public IEnumerable<IMessageRouter> Where(Expression<Func<IMessageRouter, bool>> func)
{
return _routers.Where(func.Compile());
}
Now I get this error
Object instance was not created by Moq.
Parameter name: mocked
Any ideas?
EDIT
So I tried writing another test without machine.fakes, as per Mocking methods with Expression<Func<T,bool>> parameter using Moq. Turns out it's an obvious problem. The func used in the real RoutingEngine is not being mocked
The<IMessageRouters>()
.WhenToldTo(x => x.Where(router => router.CanRoute(Param.IsAny<ProcessSkuCostUpdated>())))
.Return(new List<IMessageRouter> {Router});
The above has no bearing on the Where being executed at runtime and can't be as the func is compiled down to a private method at compile time. Seems like to mock the func, I need to push it up to an interface. Smells though as I'm pushing up internal behavior purely for testing.
I see two issues with your test code:
The expression you use for setting up the Where() call on IMessageRouters is too explicit. It should not care about what exact function is passed.
You are verifying whether Route() has been called on the Subject. Instead you should verify whether the Message has been passed to the IMessageRouter.
As an additional improvement, you can omit the Router field and use The<IMessageRouter>() directly.
[Subject(typeof(RoutingEngine))]
public class when_routing_a_message_with_fakes : WithSubject<RoutingEngine>
{
Establish that = () =>
{
Message = new MyMessage { SomeValue = 1, SomeOtherValue = 11010 };
The<IMessageRouter>().WhenToldTo(x => x.CanRoute(Message)).Return(true);
The<IMessageRouters>().WhenToldTo(x => x.Where(Param<Func<IMessageRouter, bool>>.IsAnything))
.Return(new List<IMessageRouter> { The<IMessageRouter>() });
};
Because of = () => Subject.Route(Message);
It should_route_the_message = () =>
The<IMessageRouter>().WasToldTo(x => x.Route(Message));
static MyMessage Message;
}
I see a way to avoid mocking the Func<> at all. I hope it's interesting to you :) Why not forget about the generalized Where(Func<>) method and provide the specific query method. You own the inbound messages and the router(s).
public class MessageRouters : IMessageRouters
{
public IList<IMessageRouter> _routers = new List<IMessageRouter>();
public IEnumerable<IMessageRouter> For<T>(T inbound)
{
return _routers.Where(x => x.CanRoute(inbound));
}
public void Add(IMessageRouter messageRouter)
{
_routers.Add(messageRouter);
}
}
The class under test becomes simpler (in signature, no Func<>).
public class RoutingEngine : IRoutingEngine
{
private readonly IMessageRouters _messageRouters;
public RoutingEngine(IMessageRouters messageRouters)
{
_messageRouters = messageRouters;
}
public void Route<T>(T inbound)
{
var messageRouters = _messageRouters.For(inbound);
foreach(var router in messageRouters)
router.Route(inbound);
}
}
I'm guessing you don't need to inspect the actual instance of the inbound message either, maybe you can get away with just a Type check, like
public IEnumerable<IMessageRouter> For<T>() { ... }
and
var messageRouters = _messageRouters.For<T>();
You don't have to mock any Func<>s now and you can just do an assert-was-called (or however that looks in Moq).

How to return null when accessing a moq object?

I am using Moq library for unit testing. Now what i want is that when I access my object for the first time it should return null, and when i access this on second time it should return something else.
here is my code
var mock = new Mock<IMyClass>();
mock.Setup(?????);
mock.Setup(?????);
var actual = target.Method(mock.object);
in my method i am first checking that whether mock object is null or not, if it is null then do initialize it and then do some calls on it.
bool Method(IMyClass myObj)
{
if (myObj != null)
return true;
else
{
myObj = new MyClass();
bool result = myObj.SomeFunctionReturningBool();
return result;
}
}
what to do setup for mock object,
Also i need to know how to mock this line
bool result = myObj.SomeFunctionReturningBool();
It sounds like you are trying to run two tests with one test method - maybe it would be better to split the tests into two?
You also want to initialise a new object if the method is passed null. To test this, I suggest creating a factory object responsible for creating instances of MyClass. The new code would look like:
interface IMyClassFactory
{
IMyClass CreateMyClass();
}
bool Method(IMyClass myObj, IMyClassFactory myClassFactory)
{
if (myObj != null)
{
return true;
}
myObj = myClassFactory.CreateMyClass();
return myObj.SomeFunctionReturningBool();
}
Then the tests would look like:
[Test]
public void Method_ShouldReturnTrueIfNotPassedNull()
{
Assert.That(target.Method(new MyClass()), Is.True);
}
[Test]
public void Method_ShouldCreateObjectAndReturnResultOfSomeFunctionIfPassedNull()
{
// Arrange
bool expectedResult = false;
var mockMyClass = new Mock<IMyClass>();
mockMyClass.Setup(x => x.SomeFunctionReturningBool()).Returns(expectedResult);
var mockMyFactory = new Mock<IMyClassFactory>();
mockMyFactory.Setup(x => x.CreateMyClass()).Returns(mockMyClass.Object);
// Act
var result = target.Method(null, mockMyFactory.Object);
// Assert
mockMyClass.Verify(x => x.SomeFunctionReturningBool(), Times.Once());
mockMyFactory.Verify(x => x.CreateMyClass(), Times.Once());
Assert.That(result, Is.EqualTo(expectedResult));
}
Here the factory pattern has been used to pass in an object which can create objects of IMyClass type, and then the factory itself has been mocked.
If you do not want to change your method's signature, then create the factory in the class's constructor, and make it accessible via a public property of the class. It can then be overwritten in the test by the mock factory. This is called dependency injection.
Moq - Return null - This working example simply illustrates how to return null using Moq. While the line of code is required is the commented line below, a full working example is provided below.
// _mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
public interface IShopService
{
Product GetProduct(string productId);
}
public class ShopService : IShopService
{
public Product GetProduct(string productId)
{
if (string.IsNullOrWhiteSpace(productId))
{
return new Product();
}
return new Product { Id = "8160807887984", Name = "How to return null in Moq" };
}
}
public class Shop
{
private static IShopService _shopService;
public Shop(IShopService shopService)
{
_shopService = shopService;
}
public Product GetProduct(string productId)
{
Product product = _shopService.GetProduct(productId);
return product;
}
}
[TestClass]
public class ShopTests
{
Mock<IShopService> _mockShopService;
[TestInitialize]
public void Setup()
{
_mockShopService = new Mock<IShopService>();
}
[TestMethod]
public void ShopService_GetProduct_Returns_null()
{
//Arrange
Shop shop = new Shop(_mockShopService.Object);
//This is how we return null --- all other code above is to bring this line of code home
_mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);
//Act
var actual = shop.GetProduct(It.IsAny<string>());
//Assert
Assert.IsNull(actual);
}
}
To mock a result value you can do simply:
mock.Setup(foo => foo.SomeFunctionReturningBool()).Returns(true); // or false :)
for the other question, just pass null in the unit test instead of passing mock.object and your unit test cover that too. So you basically create two unit test one with:
var actual = target.Method(mock.object);
and the other one with:
var actual = target.Method(null);
Currently your SUT is tight-coupled with MyClass implementation. You can't mock objects which are instantiated with new keyword inside your SUT. Thus you cannot test your SUT in isolation, and your test is not unit test anymore. When implementation of MyClass.SomeFunctionReturningBool will change (it will return true instead of false), tests of your SUT will fail. This shouldn't happen. Thus, delegate creation to some dependency (factory) and inject that dependency to your SUT:
[Test]
public void ShouldReturnTrueWhenMyClassIsNotNull()
{
Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
Mock<IMyClass> myClass = new Mock<IMyClass>();
var foo = new Foo(factory.Object);
Assert.True(foo.Method(myClass.Object));
}
[Test]
public void ShouldCreateNewMyClassAndReturnSomeFunctionValue()
{
bool expected = true;
Mock<IMyClass> myClass = new Mock<IMyClass>();
myClass.Setup(mc => mc.SomeFunctionReturningBool()).Returns(expected);
Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
factory.Setup(f => f.CreateMyClass()).Returns(myClass.Object);
var foo = new Foo(factory.Object);
Assert.That(foo.Method(null), Is.EqualTo(expected));
factory.VerifyAll();
myClass.VerifyAll();
}
BTW assignment new value to method parameter does not affect reference which you passed to method.
Implementation:
public class Foo
{
private IMyClassFactory _factory;
public Foo(IMyClassFactory factory)
{
_factory = factory;
}
public bool Method(IMyClass myObj)
{
if (myObj != null)
return true;
return _factory.CreateMyClass().SomeFunctionReturningBool();
}
}
You can use TestFixture with parameter. this test will run two times and different type value.
using NUnit.Framework;
namespace Project.Tests
{
[TestFixture(1)]
[TestFixture(2)]
public class MyTest
{
private int _intType;
public MyTest(int type)
{
_intType = type;
}
[SetUp]
public void Setup()
{
if (_intType==1)
{
//Mock Return false
}
else
{
//Mock Return Value
}
}
}
}

Categories

Resources