Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 测试旧代码时添加虚拟关键字_C#_Unit Testing_Rhino Mocks - Fatal编程技术网

C# 测试旧代码时添加虚拟关键字

C# 测试旧代码时添加虚拟关键字,c#,unit-testing,rhino-mocks,C#,Unit Testing,Rhino Mocks,我正在给一些粗糙的遗留代码添加测试,以便有足够的信心认真地重构它。其中一个问题是,编写代码的人显然没有试图使代码可测试(考虑到他们从未编写过单个单元测试!) 一个常见的问题是,目前没有接口,只有一个11级的深层继承链。我使用Rhino Mock将被测试的类与其依赖项隔离开来,但是当我模拟一个类而不是一个接口时,如果只读属性具有virtual关键字,我只能存根它 我目前的想法是,我只需将virtual关键字添加到属性中。没有计划向现有依赖关系链中添加任何其他对象,这将允许编写测试 是否有任何反对添

我正在给一些粗糙的遗留代码添加测试,以便有足够的信心认真地重构它。其中一个问题是,编写代码的人显然没有试图使代码可测试(考虑到他们从未编写过单个单元测试!)

一个常见的问题是,目前没有接口,只有一个11级的深层继承链。我使用Rhino Mock将被测试的类与其依赖项隔离开来,但是当我模拟一个类而不是一个接口时,如果只读属性具有
virtual
关键字,我只能存根它

我目前的想法是,我只需将
virtual
关键字添加到属性中。没有计划向现有依赖关系链中添加任何其他对象,这将允许编写测试

是否有任何反对添加
virtual
关键字的论据,或者这是一个可以接受的折衷方案,以便让测试进入?

示例代码

在测试类中:

var someClassStub = MockRepository.GenerateStub<SomeClass>();
someClassStub.Stub(s => s.SomeProperty).Return("Test");

反对添加
virtual
的主要理由是它歪曲了您的意图。
virtual
关键字向您期望此属性可能被重写的派生类发出信号

我不会使用
virtual
,而是模拟依赖关系,如下所示:

var mockedDependency = MockRepository.GenerateMock<IDependency>();
mockedDependency.Expect(x => x.SomeMethod())
                .Returns("whatever your test dictates");

var target = new SomeClass(mockedDependency);

mockedDependency.VerifyAllExpectations();
public SomeClass(IDependency dependency) : base()
{
    this.someDependency = dependency;
}

这里没有在任何地方添加
virtual
,而是提供了一些更安全的方法来使代码最初可测试。就个人而言,我强烈建议使用VisualStudio提供的“提取接口”工具,并在可能安全的情况下用接口替换具体的类引用。然后,模拟接口而不是具体的类

如果您使用的是不支持Extract接口的Visual Studio(或其他IDE)版本,那么您所要做的就是跟踪类的所有公共成员,并将它们添加到接口中,使您的具体类实现它

您的首要任务应该是获得初始测试集。通过这种方式,您可以在合理确定代码没有被破坏的情况下进行更危险的更改


对于任何致力于使旧遗留代码单元可测试的人,我强烈推荐阅读这本书。这钱很值。如此之多以至于我的经理最终给我的办公室买了一份供参考

可能会有一些副作用。一个例子是,如果这些对象中有任何一个是LINQ to SQL中使用的类型。虚拟属性将阻止LINQ查询正常运行,因为转换无法处理虚拟属性。我们在自己的代码库中遇到了同样的问题。为什么不能简单地设置属性呢?如何创建模拟(部分、动态、严格)?@RyanGates属性有一个getter,没有setter。我正在使用
mockrepository.GenerateStub()
@mellamokb创建一个存根-非常感谢您提供的信息。您还可以尝试使用Visual Studio 2012中的Fakes框架。从VS Update 2开始,它提供高级和终极SKU。Fakes框架帮助您测试遗留代码。第一段+1。您使用的示例是模拟接口,如果我可以的话,这肯定是解决方案-但我在问题中特别提到,我必须存根该类。@SteveFenton,因此您也不能模拟依赖关系?不容易-在某些情况下,依赖关系是依赖关系链上的一个属性。我认为你的观点是我为什么不应该使用虚拟机这个问题的最佳答案。我会尽量避免,但我想我会被迫使用捷径,以务实。一旦我进行了测试,我就看不到这段代码以当前的形式存在,因为我将开始进行重大更改。
public SomeClass(IDependency dependency) : base()
{
    this.someDependency = dependency;
}