0

抱歉发了这么长的帖子...

在被介绍给一个棕地项目时,我对某些单元测试集和思考什么有疑问。假设您有一个存储库类,包装了一个存储过程,并且在开发人员指南中,有一套特定的指导方针(规则),描述了应该如何构造这个类。该类可能如下所示:

public class PersonRepository
{
public PersonCollection FindPersonsByNameAndCity(string personName, string cityName)
{
    using (new SomeProfiler("someKey"))
    {
        var sp = Ioc.Resolve<IPersonStoredProcedure>();

        sp.addNameArguement(personName);
        sp.addCityArguement(cityName);

        return sp.invoke();
    }
} }

现在,我当然会编写一些集成测试,测试 SP 是否可以被调用,以及行为是否符合预期。但是,我会编写单元测试来断言:

  • 调用带有输入参数“someKey”的 SomeProfiler 的构造函数
  • PersonStoredProcedure 的构造函数被称为
  • 存储过程上的 addNameArgument 方法是用参数 personName 调用的
  • 存储过程上的 addCityArgument 方法使用参数 cityName 调用
  • 在存储过程上调用调用方法 -

如果是这样,除了行为之外,我可能会测试方法的整个结构。我最初的想法是它是矫枉过正的。然而,关于团队强制执行的编码实践,这些测试确保了统一且“正确”的结构,并且下一层被正确调用(从 DAL 到 DB,从 BLL 到 DAL 等)。

在我的例子中,这些类型的测试是针对应用程序的每一层执行的。

后续问题 - SomeProfiler 类的使用对我来说有点像约定 - 相反为此创建显式测试,是否可以通过使用静态代码分析或 unittest + 反射来创建约定样式的测试?

提前致谢。

4

2 回答 2

0

单元测试应该关注行为,而不是实现。因此,编写测试来验证某些参数是否已设置或传入并不会为您的测试策略增加太多价值。

由于提供的示例似乎与您的数据库进行通信,因此它不能真正被视为“单元测试”,因为它必须与具有其他设置和先决条件的物理依赖项进行通信,例如环境的可用性、数据库架构、现有数据,存储过程等。您编写的任何测试实际上也在验证这些先决条件。

在目前的情况下,对这些类型的测试最好的选择是测试类提供的行为——调用存储库上的方法,然后验证结果是否符合您的预期。但是,您会突然意识到这里有一个隐藏的成本——数据库在测试运行之间维护状态,您需要额外的设置或拆卸逻辑来确保数据库处于众所周知的状态。

虽然我意识到这个问题的意图是关于测试“黑匣子”,但很明显你的 API 中有一些隐藏的魔法。解决众所周知的状态问题的首选方法是使用范围为当前测试的内存数据库,这将我与环境因素隔离开来,并使我能够并行化我的集成测试。我敢打赌,在当前的设计下,没有“接缝”以编程方式引入数据库配置,因此您“陷入困境”。根据我的经验,魔法很痛。

然而,对现有设计的轻微改动解决了这个问题,“魔法”消失了:

public class PersonRepository : IPersonRepository
{
      private ConnectionManager _mgr;

      public PersonRepository(ConnectionManager mgr)
      {
         _mgr = mgr;
      }

      public PersonCollection FindPersonsByNameAndCity(string personName, string cityName)
      {
           using (var p = _mgr.CreateProfiler("somekey"))
           {
                 var sp = new PersonStoredProcedure(p);

                 sp.addArguement("name", personName);
                 sp.addArguement("city", cityName);

                 return sp.invoke();
           }
      }
}
于 2011-06-23T15:16:11.830 回答
0

我认为您最初的想法是正确的-这是矫枉过正。尽管您可以使用反射来确保该类具有您期望的方法,但我不确定您是否要以这种方式对其进行测试。

也许您应该使用诸如 FxCop/StyleCop 或 nDepend 之类的工具而不是单元测试来确保特定程序集/dll 中的所有类都具有这些属性。

话虽如此,我相信“只编写你需要的代码”为什么要测试一个方法是否存在,要么你在代码的某个地方使用它,你可以测试特定的情况,或者你不 - 所以它是无关的。

于 2011-06-22T13:53:52.003 回答