我是单位测试和嘲笑的新手。我正在研究的项目有很多方法,如下所示:
public bool MyMethod(int param, int param2)
{
using (SomeEntity dBcontext = new SomeEntity())
{
FancyObj theobj = dBcontext.MyObjs.FirstOrDefault(l => l.ObjId == param2);
if (theobj != null && theobj.CurrentSeason != param) //if season has changed then update
{
theobj .CurrentSeason = param;
dBcontext.SaveChanges();
return true;
}
return false;
}
}
我正在使用Telerik JustMock,除非我遗漏了某些东西,否则我无法模拟实体调用,因为它直接在测试方法中实例化。
我唯一的解决方案是修改方法/类以保存SomeEntity类型的属性吗?
答案 0 :(得分:2)
新建所需依赖项的实例(而不是在构造函数中请求它)会导致可测试性丧失。基本上,通过使用new
运算符,您将应用程序实例化的关注与应用程序逻辑的关注混合在一起。
依赖注入救援!您的测试类应该询问在构造函数中完成工作所需的所有事情,并依赖于接口,而不是具体的实现。这样,您就可以提供虚假的实现,使您的单元测试完全隔离。
答案 1 :(得分:1)
如果不重构您的代码,我认为您可能会对传统的模拟框架感到不快,因为所有Mock框架都依赖于virtual
或interface
的方法。
但是如果您拥有Visual Studio Premium或Ultimate版本,则可以使用Microsoft Fakes来修改/替换/拦截对非虚方法和属性的调用(通过修改/注入CIL代码到第3个程序集中)他们被装上了)。
答案 2 :(得分:1)
虽然依赖注入可能是长期更好的方法(它通常会改善代码的结构),但是像Typemock这样的商业解决方案允许您测试无法在传统方式。这是一个混合的祝福,因为你可以依赖于模拟框架,并不一定收获可以通过更传统的模拟框架进行单元测试所鼓励的结构变化。但是,它应该允许您测试您描述的情况。
来自website的示例显示了他们如何获得在其Calculate函数中创建的对象的句柄。正如其他一些示例中所示,此句柄可用于设置对该依赖项的调用的期望:
public static int Calculate(int a, int b)
{
var dependency = new Dependency();
dependency.CheckSecurity("typemock", "rules");
return a + b;
}
[TestMethod,Isolated]
public void FakeConstructor()
{
// Fake the Dependency constructor
var fakeHandle = Isolate.Fake.NextInstance<dependency>();
var result = ClassUnderTest.Calculate(1, 2);
Assert.AreEqual(3, result);
}
有各种不同的定价选项,我不确定你为每一层获得了什么,但如果你真的不想改变你的代码并且你有相当大的口袋,那么可能值得考虑。
答案 3 :(得分:0)
是的,可以使用JustMock的商业版本排列new
表达式的返回值。
var mock = Mock.Create<SomeEntity>();
Mock.Arrange(() => new SomeEntity()).Returns(mock);
从这里开始,您可以安排模拟以获得测试所需的行为。如果您正在使用EF6,那么您可以尝试插入JustMock的Telerik.JustMock.EntityFramework来为您的测试创建内存模拟数据库上下文。