假设我有这个接口和这个类:
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
}
所以我想知道我是否可以从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());
}
但是没有用,它说“System.ArgumentException:对象实例不是由Moq创建的” .
请问有什么建议吗?
在命令类中有这样的东西:
public void Execute()
{
// some code
Scheduler.GetScheduler().StopTimer();
}
3 回答
我提出了一种不同的方法,可以避免这样做......
Scheduler类正在实现单例模式来控制其构造 . 你需要能够抽象出依赖于构造方式的东西.640275_ . 所以别的东西应该负责管理调度程序的构建:它不应该负责(single responsibility principle) .
常见的方法是使用Gang-of-Four Factory method pattern或service locator pattern(例如Microsoft的UnityContainer) . 这些中的任何一个都可以被指示将该类暴露为单例,使该类只是该类负责的实现 .
Dependency Injection完成拼图,因为当类注入了它们的依赖项时,它们本身就会从它们使用的东西的构造中抽象出来 . 所以需要一个
IScheduler
的类会有一个注入并使用它 .有了这些模式,在问题中执行请求的需求就会消失,并导致代码明确分离关注点 .
脚注:我知道这些模式可能看起来令人生畏,似乎它为此做了很多努力,而且很难看到它的好处;但请相信我: try 这个(我真的是试试吧,你可以't just have a half-hearted attempt, because it is quite a step change in approach). I used to write code just like you'发布 . 我被建议看看这些模式 . 我有严重的疑虑,但我从来没有回头,现在我用这种方式编写我的所有代码 .
如果您在虚拟呼叫中打包要尝试替换的呼叫,则可以这样做:
然后在你的单元测试课:
目前还不清楚你要通过模拟测试什么 .
如果测试需要检查私有静态字段,那么利用反射将是可行的方法,但最终会得到与
Scheduler.GetScheduler()
相同的结果 .从类型中获取私有静态字段的基本方法是:
模拟对虚拟地址表起作用(在运行时,MSIL检查VAT以查找要运行的方法的地址) . 抽象基础和虚拟实例方法是可模拟的,接口也是如此 .
如果虚拟被添加到实例中的
StopTimer
的签名中,则它将是Mockable,这是从Mock<IScheduler>
获得的所有内容 .