假设我有这个接口和这个类:
public interface IScheduler
{
void StopTimer();
// some other methods
}
public class Scheduler : IScheduler
{
private static readonly IScheduler scheduler = new Scheduler();
private readonly Timer timer;
public Scheduler()
{
refreshTimer = new Timer
{
Enabled = false,
AutoReset = false
};
}
public static IScheduler GetScheduler()
{
return scheduler;
}
public void StopTimer()
{
timer.Stop();
}
// some other methods
}
Run Code Online (Sandbox Code Playgroud)
所以我想知道是否可以从 GetScheduler 方法获得一个模拟实例。我试过这样的事情:
[TestMethod]
public void Execute_ButtonClicked_StopTimer()
{
// arrange
var mockScheduler = Mock.Get(Scheduler.GetScheduler());
var command = GetCommandInstance();
// act
command.Execute();
// assert
mockScheduler.Verify(m => m.StopTimer());
}
Run Code Online (Sandbox Code Playgroud)
但没有用,它说“System.ArgumentException:对象实例不是由 Moq 创建的。”
请问有什么建议吗?
在命令类里面有这样的东西:
public void Execute()
{
// some code
Scheduler.GetScheduler().StopTimer();
}
Run Code Online (Sandbox Code Playgroud)
我提出了一种不同的方法,可以避免这样做......
Scheduler 类正在实现单例模式来控制其构造。您需要能够抽象依赖于IScheduler它的构造方式的事物。所以其他东西应该有责任管理调度器的构造:它不应该自己做,因为构造不是那个类的责任(单一责任原则)。
对此的常用方法是使用四人组工厂方法模式或服务定位器模式(例如 Microsoft 的 UnityContainer)。其中任何一个都可以指示将该类公开为单例,而使该类仅作为该类负责内容的实现。
依赖注入完成了拼图,因为当类注入它们的依赖项时,它们本身就从它们使用的事物的构造中抽象出来。所以一个需要 a 的类IScheduler会注入一个并使用它。
有了这些模式,执行问题中要求的操作的需求就消失了,并导致代码具有明确的关注点分离。
脚注:我知道这些模式的事情看起来令人生畏,而且似乎为此付出了很多努力,而且很难看到好处;但请相信我:试试这个(我的意思是尝试它,你不能只是三心二意的尝试,因为它是方法上的一个很大的变化)。我曾经像您发布的那样编写代码。我被建议看看这些模式。我有严重的怀疑,但我从未回头,现在我以这种方式编写所有代码。