应该如何使用静态和不可修改的属性和方法测试复杂对象?你的代码应该适合你将要使用的测试框架吗



我遇到了一个麻烦,"项目经理"给了我一个项目(几乎是最终产品)来测试它。

这是Silverlight中的一个大项目,我对结尾部分进行了编码。

这里有很多问题(测试),数据库连接(数据层、服务、会话存储等)在另一个项目的封闭dll中(我无法访问源代码),这些dll包含一个Collection类,如:

public class SomeCollection
{
public static SomeCollection GetCollectionByName(string name);
}

还有另一个用于控制线程、审查错误、完成/完成数据加载的实用程序类:

public static class BasicUtilities
{
public static T ExecuteAndFinish(this T baseclass, Action<T> loaded);
public static T ExecuteAndFinish(this T baseclass, Action<T> loaded, Action<bool> errors);
}

然后在ViewModel中,我需要加载数据并将其填充到某种控件中,等等。常见的调用如下:

public class SomeViewModel : ViewModelBase
{
...
SomeCollection.GetCollectionByName("AIdentifier").ExecuteAndFinish
(collectionLoaded) =>
{
//do something with the collection, populate a control, grid, listbox, etc
});
...
}

然后我想测试SomeViewModel,"澄清"我是测试新手。我可以使用两个框架,moq(用于模拟特殊模型、UtilyClass、DataProviders等)或Ninject(用于DI,我对此了解不多)。

一种方法可以是为测试重载SomeViewModel的构造函数,将模拟对象传递给SomeCollection类型的新虚拟属性,以替换所使用的通用调用:

public class SomeViewModel : ViewModelBase
{
...
SomeCollectionProperty.GetCollectionByName("AIdentifier").ExecuteAndFinish
(collectionLoaded) =>
{
//do something with the collection, populate a control, grid, listbox, etc
});
...
public virtual SomeClass SomeCollectionProperty { get; set; }
...
}

这不起作用,因为我不能模拟类SomeCollection的静态方法GetCollectionByName,更糟糕的是,我不能修改dll。

DI似乎会发生这样的事情,而且不会起作用,我不知道。

似乎我需要强制修改所有地方的代码,但我无法修改datalayer.dll(对其进行分组)。

我该怎么办?非常感谢。

请不要认为以下是非答案。你问的是"测试"而不是"单元测试">

单元测试是指对每个单独的部件进行隔离测试。它的主要优点是可以快速地确定问题代码。这在像JavaScript这样的糟糕语言中很有用,因为JavaScript不提供很多编译器检查,并且依赖测试来识别最基本的错误。单元测试几乎就像编译器告诉你"第42行出错"。它在开发过程中也很好——在应用程序中使用代码之前先测试代码段(并确信以后不必调试它)。它的缺点是它很脆弱(代码更改意味着大量的测试更改),需要大量的模拟,而且你必须仔细设计代码(这对你来说太晚了)。

集成测试将测试拼凑在一起。它的主要好处是测试更彻底(类在隔离状态下可以很好地工作,但在实际一起使用时会中断,因为它们的设计是错误的),而且它不那么脆弱。缺点是,您可能需要设置一个完整的外部环境,其中包含数据库、服务器等,以便运行测试。但是,再一次,这可以让你测试一切是否协同工作。

我认为在这一点上,您应该编写集成测试。这并不意味着牺牲代码覆盖率。如果你的应用程序中的所有代码行都能真正工作,那么完全有可能设置符合每一行代码的集成测试。

集成测试可以存在于不同的级别(最高的是功能测试——在应用程序与世界的接口上测试应用程序),因此您可以将代码分解为块,并测试每个块,而不是整个应用程序。

简短回答:
使用Typemock Isolator-它可以模拟所有东西(封闭dll中的私有静态方法,包括GetCollectionByName),但它是商业产品

答案不那么简短:
根据SOLID原则构建应用程序,实践TDD并继续重构和代码改进,本可以解决您的问题(或者说,您一开始就不会有这个问题)
您的逻辑单元将被分离,Moq将允许对所有依赖接口的类进行简单的测试
对即将完成(好的,已发货)的产品进行一些测试并不理想,但您仍然可以通过添加尽可能多的(好的)测试来增加一些价值
Typemock Isolator使用。Net探查器,在运行时注入代码,用您选择的任何行为替换真实的逻辑。这允许对私有类、静态类、密封类等进行测试。

全面披露:我曾经为Typemock工作,现在大多数项目都使用Moq(好吧,因为它是免费的)。

最新更新