I have some troubles with mocking of a local variable in a method of my class.
I try to mock my Worker class but it calls a method that returns null value and my context variable becomes null. Thereby I get an exception when try to get the Name property.
How to force CreateWorkerContext() to return mock values? May be there is a way to mock a local variable (context)?
Thanks!
My code will tell more about the problem:
namespace Moq
{
class Program
{
static void Main(string[] args)
{
var workerMock = new Mock<Worker>();
workerMock.Object.GetContextName();
}
}
public class Worker
{
public string GetContextName()
{
// something happens and context does not create (imitated situation)
WorkerContext context = CreateWorkerContext();
// exception because _context is null
return context.Name;
}
private WorkerContext CreateWorkerContext()
{
// imitate that context is not created
return null;
}
}
public class WorkerContext
{
public string Name { get; set; }
}
}
A few things are arguable here.
First, - but this is just my opinion - you should avoid having partial mocking (partial mocking = mock an abstract class that doesn't implement an interface, and therefore, keeps the original implementation of the methods which weren't mocked.). The best would be to have an IWorker interface which Worker would imlepement.
Second - I would create strict mocks. Loose mocks seem like a nice shortcut, but often will let your methods and properties return the default value when you don't intend to (null in your case)
Third - I would Inject WorkerContext. If you can't inject it because you need to parametrize it with come .ctor arguments, then inject a WorkerContextFactory which will allow you to mock the creation and parametrization of your WorkerContext
Dynamic mock libraries like Moq are, in general, not magic. They can only replace the behaviour that you yourself could replace with code.
In this particular example, Moq can't replace CreateWorkerContext because it's a private method.
One option is to make it virtual:
public class Worker
{
public string GetContextName()
{
WorkerContext context = CreateWorkerContext();
return context.Name;
}
public virtual WorkerContext CreateWorkerContext()
{
return new WorkerContext();
}
}
Another option would be to replace the CreateWorkerContext method with a Strategy:
public class Worker
{
private readonly IWorkerContextFactory factory;
public Worker(IWorkerContextFactory factory)
{
if (factory == null)
throw new ArgumentNullException(nameof(factory));
this.factory = factory;
}
public string GetContextName()
{
WorkerContext context = this.factory.Create();
return context.Name;
}
}
Both of these options would enable Moq to simulate the desired behaviour.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With