Mocking delegates with Moq - c#

I have an interface:
public interface IRepeater
{
void Each(string path, Action<string> action);
}
I want to mock this interface using Moq. Now I can obviously do the following:
var mock = new Mock<IRepeater>();
mock.Setup(m => m.Each(It.IsAny<string>(), It.IsAny<Action<string>>());
However, to aid testing I want to be able to mock the string that gets passed to the Action<string>. Can this be done with Moq? If yes, how?
Update
To clarify I am testing a different class that has a dependency on IRepeater. I want to mock IRepeater.Each so I can control the string that the Action gets so I can test the behaviour.
Example
So if I have a class like so.
public class Service
{
private readonly IRepeater _repeater;
public Service(IRepeater repeater)
{
_repeater = repeater;
}
public string Parse(string path)
{
var builder = new StringBuilder();
_repeater.Each(path, line => builder.Append(line));
return builder.ToString();
}
}
How do I mock IRepeater.Each so that I can test Service.Parse?

You have to use callback method. Since line => builder.Append(line) is part of the method behavior, you have to execute this behavior when you test the method:
[TestMethod]
public void Test_Service_When_Passing_String_And_ActionDelegate()
{
var fakeReporter = new Mock<IRepeater>();
fakeReporter.Setup(x => x.Each(It.IsAny<string>(), It.IsAny<Action<string>>()))
.Callback<string, Action<string>>((s, action) => action(s));
var target = new Service(fakeReporter.Object);
var result = target.Parse("asdfghj");
Assert.AreEqual("asdfghj", result);
}
Another approach to test this method is to verify the method was called with the correct path and then verify that the action is the correct action:
[TestMethod]
public void Test_Service_When_Passing_String_And_ActionDelegate()
{
var fakeReporter = new Mock<IRepeater>();
fakeReporter.Setup(x => x.Each(It.IsAny<string>(), It.IsAny<Action<string>>()))
.Callback<string, Action<string>>((s, action) =>
{
Assert.AreEqual("asdfghj", s);
foreach (var w in "pass")
{
action(w.ToString());
}
});
var target = new Service(fakeReporter.Object);
var result = target.Parse("asdfghj");
Assert.AreEqual("pass", result);
}
BTW you can replace the It.IsAny<string>() with the string and then remove the Assert.AreEqual("asdfghj", s);(I just like to test things in the explicit way...)

Seems like you are looking to verify that a passed Action (delegate) will be passed to the IRepeater Call. Because you are not testing the Repeater but a Repeater caller (The Repeater is the mock and not the tested subject).
Here is how I would have done it:
public class Service
{
private readonly IRepeater repeater;
public Service(IRepeater repeater)
{
this.repeater = repeater;
}
public void Foo(string str, Action<string> action)
{
repeater.Each(str, action);
}
}
public class ActionImplement
{
public virtual void Action(string str)
{
Console.Write(str);
}
}
public interface IRepeater
{
void Each(string path, Action<string> action);
}
And the test would have verify the passing of ActionImplement.Action
[TestMethod]
public void Test_Service_When_Passing_String_And_ActionDelegate()
{
var actionImplement = new Mock<ActionImplement>();
actionImplement.Setup(m => m.Action(It.IsAny<string>()));
var mock = new Mock<IRepeater>();
mock.Setup(m => m.Each(It.IsAny<string>(), actionImplement.Object.Action));
var srv = new Service(mock.Object);
srv.Foo("aa",actionImplement.Object.Action);
mock.Verify(ai => ai.Each("aa", actionImplement.Object.Action));
}

Related

How to create mock for method that is called using object instance in MOQ C#?

I created Test for a method that is being tested using MOQ & NUnit. The method to be tested will will another method using an object of that corresponding class. When I try to mock that called method, I am not able to invoke the mocked method. How to mock this method, because my testing method is using the other said method. Please help me on this.
public DataSet ExecuteCondition()
{
var ObjClass1 = new Class1();
....
var result = ObjClass1.VerifyPrecondition(query);
....
}
public class Class1:IClass1
{
public string VerifyPrecondition(string query)
{
....
return text;
}
}
So, I suppose this should look like this:
Class with ExecuteCondition() method:
public class DataClass
{
private readonly IClass1 _class1;
public DataClass(IClass1 class1)
{
_class1 = class1;
}
public DataSet ExecuteCondition()
{
//....
var result = _class1.VerifyPrecondition(query);
//....
}
}
Test:
[Test]
public void Test()
{
var mockClass1 = new Mock<IClass1>();
mockClass1.Setup(x => x.VerifyPrecondition(It.IsAny<string>())).Returns("test");
var dataClass = new DataClass(mockClass1.Object);
dataClass.ExecuteCondition();
//Assert
}

Mocking Hangfire RecurringJob Dependency in .Net Core 2

Consider the following controller:
public class SubmissionController : Controller
{
public SubmissionController()
{ }
public IActionResult Post()
{
RecurringJob.AddOrUpdate(() => InitiateSubmission(), Cron.Minutely);
return Ok("Periodic submission triggered");
}
}
Does Hangfire offer an abstraction inject a dependency for RecurringJob class? I have done some research and the only available abstraction is IBackgroundJobClient, which does not have the option to schedule a recurring job.
I need to verify that the job has been added in a unit test.
If you check the source code of RecurringJob class, you will see that its static methods result in call to RecurringJobManager class:
public static class RecurringJob
{
private static readonly Lazy<RecurringJobManager> Instance = new Lazy<RecurringJobManager>(
() => new RecurringJobManager());
// ...
public static void AddOrUpdate(
Expression<Action> methodCall,
string cronExpression,
TimeZoneInfo timeZone = null,
string queue = EnqueuedState.DefaultQueue)
{
var job = Job.FromExpression(methodCall);
var id = GetRecurringJobId(job);
Instance.Value.AddOrUpdate(id, job, cronExpression, timeZone ?? TimeZoneInfo.Utc, queue);
}
// ...
}
RecurringJobManager implements IRecurringJobManager interface which you could use for dependency injection and mock in UT.
However RecurringJob has internal logic for getting a job from lambda and building a job id:
var job = Job.FromExpression(methodCall);
var id = GetRecurringJobId(job);
Job.FromExpression() is a public method that you can safely use. However GetRecurringJobId is a private method defined as following:
private static string GetRecurringJobId(Job job)
{
return $"{job.Type.ToGenericTypeString()}.{job.Method.Name}";
}
GetRecurringJobId basically returns name of job method in form of SubmissionController.InitiateSubmission. It's based on internal class TypeExtensions with extension methods for Type. You can't use this class directly since it is internal, so you should duplicate that logic.
If you follow this approach your final solution would be:
TypeExtensions (copied from Hangfire sources):
static class TypeExtensions
{
public static string ToGenericTypeString(this Type type)
{
if (!type.GetTypeInfo().IsGenericType)
{
return type.GetFullNameWithoutNamespace()
.ReplacePlusWithDotInNestedTypeName();
}
return type.GetGenericTypeDefinition()
.GetFullNameWithoutNamespace()
.ReplacePlusWithDotInNestedTypeName()
.ReplaceGenericParametersInGenericTypeName(type);
}
private static string GetFullNameWithoutNamespace(this Type type)
{
if (type.IsGenericParameter)
{
return type.Name;
}
const int dotLength = 1;
// ReSharper disable once PossibleNullReferenceException
return !String.IsNullOrEmpty(type.Namespace)
? type.FullName.Substring(type.Namespace.Length + dotLength)
: type.FullName;
}
private static string ReplacePlusWithDotInNestedTypeName(this string typeName)
{
return typeName.Replace('+', '.');
}
private static string ReplaceGenericParametersInGenericTypeName(this string typeName, Type type)
{
var genericArguments = type.GetTypeInfo().GetAllGenericArguments();
const string regexForGenericArguments = #"`[1-9]\d*";
var rgx = new Regex(regexForGenericArguments);
typeName = rgx.Replace(typeName, match =>
{
var currentGenericArgumentNumbers = int.Parse(match.Value.Substring(1));
var currentArguments = string.Join(",", genericArguments.Take(currentGenericArgumentNumbers).Select(ToGenericTypeString));
genericArguments = genericArguments.Skip(currentGenericArgumentNumbers).ToArray();
return string.Concat("<", currentArguments, ">");
});
return typeName;
}
public static Type[] GetAllGenericArguments(this TypeInfo type)
{
return type.GenericTypeArguments.Length > 0 ? type.GenericTypeArguments : type.GenericTypeParameters;
}
}
RecurringJobManagerExtensions:
public static class RecurringJobManagerExtensions
{
public static void AddOrUpdate(this IRecurringJobManager manager, Expression<Action> methodCall, Func<string> cronExpression, TimeZoneInfo timeZone = null, string queue = EnqueuedState.DefaultQueue)
{
var job = Job.FromExpression(methodCall);
var id = $"{job.Type.ToGenericTypeString()}.{job.Method.Name}";
manager.AddOrUpdate(id, job, cronExpression(), timeZone ?? TimeZoneInfo.Utc, queue);
}
}
Controller with injected IRecurringJobManager:
public class SubmissionController : Controller
{
private readonly IRecurringJobManager recurringJobManager;
public SubmissionController(IRecurringJobManager recurringJobManager)
{
this.recurringJobManager = recurringJobManager;
}
public IActionResult Post()
{
recurringJobManager.AddOrUpdate(() => InitiateSubmission(), Cron.Minutely);
return Ok("Periodic submission triggered");
}
public void InitiateSubmission()
{
// ...
}
}
Well, this approach will work, but I'm not a fan of it. It's based on some internal Hangfire stuff that could be changed in the future.
That's why I suggest to use another approach. You could add new facade interface (e.g. IRecurringJobFacade) which will mimic methods from RecurringJob that you are going to use. Implementation of this interface will just call corresponding RecurringJob methods. Then you inject this IRecurringJobFacade into the controller and could easily mock it in UT. Here is a sample:
IRecurringJobFacade:
public interface IRecurringJobFacade
{
void AddOrUpdate(Expression<Action> methodCall, Func<string> cronExpression);
// Mimic other methods from RecurringJob that you are going to use.
// ...
}
RecurringJobFacade:
public class RecurringJobFacade : IRecurringJobFacade
{
public void AddOrUpdate(Expression<Action> methodCall, Func<string> cronExpression)
{
RecurringJob.AddOrUpdate(methodCall, cronExpression);
}
}
Controller with injected IRecurringJobFacade:
public class SubmissionController : Controller
{
private readonly IRecurringJobFacade recurringJobFacade;
public SubmissionController(IRecurringJobFacade recurringJobFacade)
{
this.recurringJobFacade = recurringJobFacade;
}
public IActionResult Post()
{
recurringJobFacade.AddOrUpdate(() => InitiateSubmission(), Cron.Minutely);
return Ok("Periodic submission triggered");
}
public void InitiateSubmission()
{
// ...
}
}
As you see this approach is much simpler and most importantly it's much more reliable, since it does not dig into Hangfire internals and just calls RecurringJob methods as usual.
Such facade interface is often used when code could not be mocked directly (static methods or classes not based on interfaces). Some other examples that I have used in my practice: mock of System.IO.File, DateTime.Now, System.Timers.Timer, etc.
I had a similar case with: RecurringJob.RemoveIfExists. I try this (I see the original code in github and setup my mock's):
private void SetupHangfire()
{
Mock<JobStorage> _jobStorageMock = new Mock<JobStorage>();
Mock<IStorageConnection> _storageConnectionMock = new Mock<IStorageConnection>();
Mock<IWriteOnlyTransaction> _transactionConnectionMock = new Mock<IWriteOnlyTransaction>();
JobStorage.Current = _jobStorageMock.Object;
_jobStorageMock
.Setup(y => y.GetConnection())
.Returns(_storageConnectionMock.Object);
_storageConnectionMock
.Setup(y => y.AcquireDistributedLock(It.IsAny<string>(), It.IsAny<TimeSpan>()))
.Returns(_transactionConnectionMock.Object);
_storageConnectionMock
.Setup(y => y.CreateWriteTransaction())
.Returns(_transactionConnectionMock.Object);
_transactionConnectionMock
.Setup(y => y.RemoveHash(It.IsAny<string>()));
_transactionConnectionMock
.Setup(y => y.RemoveFromSet(It.IsAny<string>(), It.IsAny<string>()));
_transactionConnectionMock
.Setup(y => y.Commit());
}

How can I get StructureMap's AutoMocker to mock fake data?

I'm currently trying to implement StructureMap's AutoMocking functionality and I need help with getting the mocked .
I have a Test method as follows:
[Test]
public void DirctoryResult_Returns_Groups()
{
var autoMocker = new RhinoAutoMocker<GroupController>(MockMode.AAA);
GroupController controller = autoMocker.ClassUnderTest;
var directoryResult = controller.DirectoryResult("b");
var fundDirectoryViewModel = (FundDirectoryViewModel)directoryResult.ViewData.Model;
Assert.IsNotNull(fundDirectoryViewModel.Groups);
}
Currently the test is failing because fundDirectoryViewModel.Groups is null.
The real implementation of DirectoryResult is as follows:
private readonly IGroupService _groupService;
public PartialViewResult DirectoryResult(string query)
{
return PartialView(new FundDirectoryViewModel
{
Groups =_groupService.GetGroupsByQuery(query)
});
}
where _groupService.GetGroupsByQuery(query) uses an interface to IGroupRepository to read data from the database. Of course, I don't want my test to read data from the actual database, but can somebody tell me how to get mock data for it?
What do I need to do to get the AutoMocker to mock the fake data for me?
update:
for reference, this is the definition of GroupService & GroupRepository
public class GroupService : IGroupService
{
private readonly IGroupRepository _groupRepository;
public GroupService(IGroupRepository groupRepository)
{
_groupRepository = groupRepository;
}
public IList<CompanyGroupInfo> GetGroupsByQuery(string query)
{
return _groupRepository.GetGroupsByQuery(query);
}
}
public class GroupRepository : DataUniverseRepository, IGroupRepository
{
public GroupRepository(ISession session)
{
_session = session;
}
public IList<CompanyGroupInfo> GetGroupsByQuery(string query)
{
// dig into the database and return stuff with _session..
}
}
I've been informed that the question was wrong. Automocker doesn't mock data like that. It's up to me to specify the fake data with Rhino Mocks.
This works:
[Test]
public void DirctoryResult_Returns_Groups()
{
var service = autoMocker.Get<IGroupService>();
service.Expect(srv => srv.GetGroupsByQuery(Arg<string>.Is.Anything))
.Return(new List<CompanyGroupInfo>
{
new CompanyGroupInfo(),
new CompanyGroupInfo(),
new CompanyGroupInfo()
});
service.Replay();
var directoryResult = _controller.DirectoryResult("b");
var fundDirectoryViewModel = (FundDirectoryViewModel)directoryResult.ViewData.Model;
Assert.That(fundDirectoryViewModel.Groups.Count, Is.EqualTo(3));
service.AssertWasCalled(srv => srv.GetGroupsByQuery(Arg<string>.Is.Equal("b")));
}

How can I mock this asynchronous method?

I have a class that roughly looks like this:
public class ViewModel
{
public ViewModel(IWebService service)
{
this.WebService = service;
}
private IWebService WebService{get;set;}
private IEnumerable<SomeData> MyData{get;set;}
private void GetReferenceData()
{
this.WebService.BeginGetStaticReferenceData(GetReferenceDataOnComplete, null);
}
private void GetReferenceDataOnComplete(IAsyncResult result)
{
this.MyData = this.WebService.EndGetStaticReferenceData(result);
}
.
.
.
}
I want to mock my IWebService interface so that when BeginGetStaticReferenceData is called it is able to call the callback method. I'm using Moq and I can't work out how to do this. My unit test set up code looks something like:
//Arrange
var service = new Mock<IWebService>();
service.Setup(x => x.BeginGetStaticReferenceData(/*.......don't know.....*/));
service.Setup(x => x.EndGetStaticReferenceData(It.IsAny<IAsyncResult>())).Returns(new List<SomeData>{new SomeData{Name="blah"}});
var viewModel = new ViewModel(service.Object);
.
.
Here's how:
[TestMethod]
public void Test10()
{
var expectedData = new[]{new SomeData(), new SomeData()};
AsyncCallback callback = null;
IAsyncResult ar = new Mock<IAsyncResult>().Object;
var webServiceStub = new Mock<IWebService>();
webServiceStub
.Setup(ws => ws.BeginGetStaticReferenceData(It.IsAny<AsyncCallback>(), null))
.Callback((AsyncCallback cb, object state) => callback = cb)
.Returns(ar);
webServiceStub
.Setup(ws => ws.EndGetStaticReferenceData(It.IsAny<IAsyncResult>()))
.Returns(expectedData);
var sut = new ViewModel(webServiceStub.Object);
sut.DoIt();
callback(ar);
Assert.AreEqual(expectedData, sut.MyData);
}
This test assumes a slightly modified ViewModel where I added a few public members to have something against which to test:
public class ViewModel
{
public ViewModel(IWebService service)
{
this.WebService = service;
}
public IEnumerable<SomeData> MyData { get; set; }
public void DoIt()
{
this.GetReferenceData();
}
private IWebService WebService { get; set; }
private void GetReferenceData()
{
this.WebService.BeginGetStaticReferenceData(GetReferenceDataOnComplete, null);
}
private void GetReferenceDataOnComplete(IAsyncResult result)
{
this.MyData = this.WebService.EndGetStaticReferenceData(result);
}
}
This article contains a very good explanation on how to test async methods using Rhino Mocks - I'm sure it can be easily adapted to use Moq instead.

Returning a function pointer

I'm trying to create a url builder similar to the one in asp mvc except our methods are frequently changing parameters and breaking pages.
Does anyone know if it's possible to coerce c# into allowing event like syntax to be returned from a delegate like this:
new UrlBuilder2<FakeController>(x => { return x.ActionWithInt; });
The class would be similar to this:
public class UrlBuilder<TController>
{
public UrlBuilder2(Func<TController, TType> action)
{
}
}
Basically I want to know what Type to use for TType. Or if it's at all possible.
Edit -
I would (if possible) like to use just the method, similar to how you would assign an event ( clickEvent =+ myMethod;)
Not exactly sure what you want to achieve, but assuming you want to generate link simlar to this:
MyForm/MyMethod.aspx
based on WebForm (or any other class) like this:
public class MyForm {
public void MyMethod() {
// Something here
}
public void MethodWithParams(int i, string str) {
// Something here
}
}
You can use this builder (test included):
class UrlBuilder2<T> {
private readonly Expression<Func<T, object>> callExpression;
public UrlBuilder2(Expression<Func<T,object>> callExpression) {
this.callExpression = callExpression;
}
public override string ToString() {
MethodCallExpression call = (MethodCallExpression) callExpression.Body;
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}/{1}.aspx", call.Object.Type.Name, call.Method.Name);
var delimiter = "?";
var formalParams = call.Method.GetParameters();
for (int i = 0; i < formalParams.Length; i++) {
var actual = call.Arguments[i];
if (actual == null)
continue; // Do not put NULL to QueryString
var formal = formalParams[i].Name;
sb.AppendFormat("{0}{1}={2}", delimiter, formal, HttpUtility.HtmlEncode(actual.ToString()));
}
return sb.ToString();
}
}
[Test]
public void CanBuildUrlByClassAndMethodName() {
var str = new UrlBuilder2<MyForm>(c => c.MyMethod()).ToString();
str.Should().Be.EqualTo("MyForm/MyMethod.aspx");
}
[Test]
public void CanBuildUrlByMethodWithParams() {
var str = new UrlBuilder2<MyForm>(c => c.MethodWithParams(2, "hello")).ToString();
str.Should().Be.EqualTo("MyForm/MyMethod.aspx?i=2&str=hello");
}
All this will allow you to keep the links type-safe and refactoring advantages will be leveraged.
You will probably need to enhance the UrlBuilder2 but this should get you started.
If you just want to use name of a method to generate links you can do something like this:
class MyClass {
public void MyMethod() {}
}
class UrlBuilder3<T> {
Expression<Func<T, Action>> info;
public UrlBuilder3(Expression<Func<T, Action>> info) {
this.info = info;
}
public override string ToString() {
UnaryExpression exp = (UnaryExpression)info.Body;
MethodCallExpression createDelegate = (MethodCallExpression)exp.Operand;
// 0-Action,1-x,2-Delegate as Constant
ConstantExpression methodArgument = (ConstantExpression)createDelegate.Arguments[2];
MethodInfo method = (MethodInfo)methodArgument.Value;
return string.Format("{0}/{1}.aspx", typeof(T).Name, method.Name);
}
}
[Test]
public void UrlByDelegate() {
new UrlBuilder3<MyClass>(x => x.MyMethod).ToString()
.Should().Be.EqualTo("MyClass/MyMethod.aspx");
}
The tricky thing is correctly resolving the Expression tree. The code above works for this particular sample, but you will need to check it works for all your cases.
You can return a function pointer aka a delegate in c# as below.
public delegate int mydelegate(string s);
public class Test
{
mydelegate MyFunc(string s)
{
return (astring => astring.Length + s.Length);
}
}
This would allow you to attach the output of the function to an event.
var test = new Test();
someevent += test.MyFunc("this is a test");
Assuming that someevent took a function with the same signature as the delegate.

Categories