在调用方法中模拟局部变量

时间:2015-10-09 09:00:33

标签: c# class unit-testing moq

我在班级的方法中嘲笑局部变量时遇到了一些麻烦。

我尝试模拟我的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; }
    }
}

2 个答案:

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