我在班级的方法中嘲笑局部变量时遇到了一些麻烦。
我尝试模拟我的Worker类,但它调用一个返回null值的方法,我的上下文变量变为null。因此,当我尝试获取Name属性时,我得到一个异常。
如何强制CreateWorkerContext()
返回模拟值?可能有办法模拟局部变量(context
)?
谢谢!
我的代码会详细说明问题:
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; }
}
}
答案 0 :(得分:5)
这里有一些事情可以论证。
首先, - 但这只是我的意见 - 你应该避免部分嘲笑(部分模拟=模拟一个没有实现接口的抽象类,因此,保留原始实施那些没有被嘲笑的方法。最好的方法是拥有一个IWorker
接口,Worker
会使用。{/ p>
第二次 - 我会创建严格的模拟。松散的模拟看起来像是一个很好的快捷方式,但通常会让你的方法和属性在你不打算(null
你的情况下)时返回默认值
第三次 - 我会注入WorkerContext
。如果你不能注入它,因为你需要使用come .ctor参数对其进行参数化,然后注入一个WorkerContextFactory
,这将允许你模拟WorkerContext
的创建和参数化
答案 1 :(得分:3)
像Moq这样的动态模拟库通常不是魔术。 They can only replace the behaviour that you yourself could replace with code
在此特定示例中,Moq无法替换CreateWorkerContext
,因为它是私有方法。
一种选择是virtual
:
public class Worker
{
public string GetContextName()
{
WorkerContext context = CreateWorkerContext();
return context.Name;
}
public virtual WorkerContext CreateWorkerContext()
{
return new WorkerContext();
}
}
另一种选择是将CreateWorkerContext
方法替换为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;
}
}
这两个选项都可以使Moq模拟所需的行为。