Unit testing 单元测试:对单例进行类型模拟
我正在使用TypeMock Isolater为一些单元测试模拟一些对象——尝试使用AAA api(因此隔离调用) 我有一个简单的单例类,在其中调用静态GetInstance(),然后返回该类的一个实例。我原以为这将是一个简单的模拟问题,但我遇到了一个非常令人沮丧的问题!我似乎无法使GetInstance()在设置预期调用的情况下正确返回模拟对象 我试过:Unit testing 单元测试:对单例进行类型模拟,unit-testing,mocking,typemock,Unit Testing,Mocking,Typemock,我正在使用TypeMock Isolater为一些单元测试模拟一些对象——尝试使用AAA api(因此隔离调用) 我有一个简单的单例类,在其中调用静态GetInstance(),然后返回该类的一个实例。我原以为这将是一个简单的模拟问题,但我遇到了一个非常令人沮丧的问题!我似乎无法使GetInstance()在设置预期调用的情况下正确返回模拟对象 我试过: 使用MST项目(使用访问器类)将模拟对象直接分配给实例变量(使用Memers.mustSpecificReturnValues和Isolat
- 使用MST项目(使用访问器类)将模拟对象直接分配给实例变量(使用Memers.mustSpecificReturnValues和Isolate.WhenCalled使用WithExactArguments设置期望值假装对象),但由于某些原因,模拟对象始终返回null(没有异常)
- 模拟Singleton.GetInstance()以返回模拟的对象。这将返回一个模拟对象,该对象需要设置WhenCalled,但现在我所做的Isolate.WhenCalled调用似乎对假对象没有任何作用-因此所有调用都会引发意外的调用异常
- 我还尝试模拟实际的方法调用(例如Singleton.GetInstance().Test()),这将适用于对该方法的调用,但对Singleton上其他方法的所有其他调用都会返回null,而不是按照我的要求引发异常(因为这似乎会自动模拟没有成员的所有对象。MustSpecifyReturnValues)
James最好的解决方案是不使用单例(或任何其他静态可变数据)。只需创建一个实例并使用依赖项注入将其传递给所有需要它的对象
[TestMethod]
public void SetBhaciorOnSingleton()
{
var fake = Isolate.Fake.Instance<SingletonClass>();
Isolate.WhenCalled(() => fake.SomeFunction()).WillReturn(10);
// Set additional behavior on singleton class
Isolate.Swap.NextInstance<SingletonClass>().With(fake);
// This is where the class constructor is being called
var result = SingletonClass.GetInstace().SomeFunction();
Assert.AreEqual(10, result );
}
[TestMethod]
公共空间设置为Haciooronsingleton()
{
var fake=Isolate.fake.Instance();
孤立.WhenCalled(()=>false.SomeFunction()).WillReturn(10);
//在singleton类上设置其他行为
使用(false)隔离.Swap.NextInstance();
//这是调用类构造函数的地方
var result=SingletonClass.getInstance().SomeFunction();
断言。等于(10,结果);
}
除非在测试之前创建singleton类,否则此解决方案应该适用于大多数场景。
如果需要在创建类后设置行为,只需在调用时使用:
[TestMethod]
public void SetBhaciorOnSingleton()
{
var fake = Isolate.Fake.Instance<SingletonClass>();
Isolate.WhenCalled(() => fake.SomeFunction()).WillReturn(10);
Isolate.WhenCalled(() => SingletonClass.GetInstace()).WillReturn(fake);
var result = SingletonClass.GetInstace().SomeFunction();
Assert.AreEqual(10, result );
}
[TestMethod]
公共空间设置为Haciooronsingleton()
{
var fake=Isolate.fake.Instance();
孤立.WhenCalled(()=>false.SomeFunction()).WillReturn(10);
隔离.WhenCalled(()=>SingletonClass.getInstance()).WillReturn(false);
var result=SingletonClass.getInstance().SomeFunction();
断言。等于(10,结果);
}
谢谢
我以前没有尝试NextInstance,因为它在我不想更改的接口上不起作用
但是,我已经尝试过了,它确实有效——尽管我假设设置何时调用的顺序并不重要,但它确实起作用。例如,如果我在交换之后进行WhenCalled,它就不起作用了。它需要在交换之前完成。(老实说,对我来说没有什么意义——它应该是同一个对象)
然而,最后一个例子(我尝试过的方法之一)对我不起作用。我伪造,在伪造上设置Expection,然后在Singleton上设置期望值以返回伪造的实例-但现在它返回具体的实例
这可能与调用构造函数的方式有关吗?我记得看到一些关于那个的
或者,我可以使用交换,但是,我希望能够在TestSetup中设置所有这些内容,并在实际测试中对预期进行微小的修改,但这看起来不可能 免责声明我在Typemock工作 您不需要模拟Singleton.GetInstance()。使用Isolate.Fake.AllInstances()而不是Isolate.Fake.Instance()可以模拟单例。然后,通过将行为设置为应用于所有实例的假单例行为 看看这个例子:
public class Singleton
{
private Singleton() { }
static readonly Singleton instance = new Singleton();
public static Singleton Instance { get { return instance; } }
public int ReturnZero()
{
return 0;
}
}
[TestMethod]
public void FakeSingleton()
{
// Here we are setting the same behavior on all instances.
// The behavior we set on fake will apply to past instance as well
var fakeSingleton = Isolate.Fake.AllInstances<Singleton>();
Isolate.WhenCalled(() => fakeSingleton.ReturnZero()).WillReturn(10);
// Assert that the behavior works.
Assert.AreEqual(10, Singleton.Instance.ReturnZero());
}
公共类单例
{
私有单例(){}
静态只读单例实例=新单例();
公共静态单例实例{get{return Instance;}}
公共int ReturnZero()
{
返回0;
}
}
[测试方法]
公开作废伪造文件()
{
//在这里,我们在所有实例上设置相同的行为。
//我们设置为false的行为也将应用于过去的实例
var fakeSingleton=Isolate.Fake.AllInstances();
当调用(()=>fakeSingleton.ReturnZero())时,将返回(10);
//断言该行为有效。
AreEqual(10,Singleton.Instance.ReturnZero());
}