调用方法时模拟局部变量

本文关键字:局部变量 模拟 方法 调用 | 更新日期: 2023-09-27 18:16:49

我在类的方法中模拟局部变量时遇到了一些麻烦。

我试图模拟我的工人类,但它调用一个方法,返回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; }
    }
}

调用方法时模拟局部变量

这里有几点值得商榷。

首先, -但这只是我的意见-您应该避免部分模拟(部分模拟=模拟不实现接口的抽象类,因此保留未被模拟的方法的原始实现)。最好是有一个Worker可以实现的IWorker接口。

-我会创建严格的模拟。松散模拟似乎是一个很好的快捷方式,但通常会让您的方法和属性在您不打算返回默认值时返回默认值(在您的示例中为null)

第三 -我会注射WorkerContext。如果你不能注入它,因为你需要用。ctor参数来参数化它,那么注入一个WorkerContextFactory,它将允许你模拟WorkerContext

的创建和参数化。

像Moq这样的动态模拟库通常不是魔法。它们只能代替你自己可以用代码代替的行为。

在这个特殊的例子中,Moq不能代替CreateWorkerContext,因为它是一个私有方法。

一个选项是将其设置为virtual:

public class Worker
{
    public string GetContextName()
    {
        WorkerContext context = CreateWorkerContext();
        return context.Name;
    }
    public virtual WorkerContext CreateWorkerContext()
    {
        return new WorkerContext();
    }
}

另一个选择是将CreateWorkerContext方法替换为策略:

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能够模拟所需的行为。