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

时间:2012-12-16 18:38:44

标签: c# silverlight unit-testing design-patterns mocking

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

这是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类型的新Virtual属性,该属性替换使用的公共调用:

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(将其分组)。

我要做什么? 非常感谢。

2 个答案:

答案 0 :(得分:1)

请不要将以下内容视为不答复。你问过“测试”而非“单元测试”。

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

集成测试测试各个部分。它的主要好处是测试更彻底(类可以单独工作,但实际一起使用时会因为设计错误而中断),而且它的脆弱性要小得多。缺点是您可能需要使用数据库,服务器等设置整个外部环境,以便运行测试。但是,再一次,这可以让你测试一切都能协同工作。

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

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

答案 1 :(得分:0)

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

简短回答:
根据{{​​3}}原则构建应用程序,实践TDD并继续重构和代码改进,可以解决您的问题(或者您首先不会遇到此问题)。
您的逻辑单元将被分开,Moq将允许您轻松测试所有依赖于接口的类 在接近完成(运输良好,已发货)的产品上进行一些测试并不理想,但您仍然可以通过添加尽可能多的(良好)测试来增加一些价值。
Typemock Isolator通过在运行时注入代码来使用.Net分析器,通过您选择的任何行为替换实际逻辑。这允许测试私有,静态,密封类等。

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