在调用方法中模拟局部变量
Mocking local variable in calling method
我在 class 的方法中模拟局部变量时遇到了一些麻烦。
我尝试模拟我的 Worker class,但它调用了一个方法,该方法使 return 的空值和我的上下文变量变为空。因此,当我尝试获取名称 属性.
时出现异常
如何强制 CreateWorkerContext()
到 return 模拟值?可能有一种模拟局部变量的方法(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; }
}
}
这里有几件事是有争议的。
首先,-但这只是我的意见-你应该避免部分模拟(部分模拟=模拟一个没有实现接口的抽象class ,因此,保留了未被模拟的方法的原始实现。)。最好的办法是有一个 IWorker
接口,Worker
可以实现。
其次 - 我会创建严格的模拟。松散的模拟似乎是一个不错的捷径,但通常会让您的方法和属性 return 在您不打算使用默认值时使用(null
在您的情况下)
第三 - 我会注入 WorkerContext
。如果你不能注入它,因为你需要用 come .ctor 参数对其进行参数化,那么注入一个 WorkerContextFactory
这将允许你模拟你的 WorkerContext
的创建和参数化
一般来说,像 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 能够模拟所需的行为。
我在 class 的方法中模拟局部变量时遇到了一些麻烦。
我尝试模拟我的 Worker class,但它调用了一个方法,该方法使 return 的空值和我的上下文变量变为空。因此,当我尝试获取名称 属性.
时出现异常如何强制 CreateWorkerContext()
到 return 模拟值?可能有一种模拟局部变量的方法(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; }
}
}
这里有几件事是有争议的。
首先,-但这只是我的意见-你应该避免部分模拟(部分模拟=模拟一个没有实现接口的抽象class ,因此,保留了未被模拟的方法的原始实现。)。最好的办法是有一个 IWorker
接口,Worker
可以实现。
其次 - 我会创建严格的模拟。松散的模拟似乎是一个不错的捷径,但通常会让您的方法和属性 return 在您不打算使用默认值时使用(null
在您的情况下)
第三 - 我会注入 WorkerContext
。如果你不能注入它,因为你需要用 come .ctor 参数对其进行参数化,那么注入一个 WorkerContextFactory
这将允许你模拟你的 WorkerContext
一般来说,像 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 能够模拟所需的行为。