我最近提出了一个关于将业务逻辑与数据访问分离以使应用程序可测试的最佳方法的问题( here )。感谢 Jeff Sternal,我创建了数据访问接口(interface),并将其具体实现从应用程序顶层传递给 BL。但现在我试图弄清楚如何将文件访问方法与业务逻辑分开。
假设我有一个函数,可以将数据从数据库加载到数据集中,格式化加载的数据(格式存储在某些外部 xml 文件中),最后将数据集序列化到文件。因此,为了支持可测试性,我需要将访问文件系统的所有函数移至某个接口(interface)。但首先 - 我发现调用 dataset.WriteXml(file) 非常方便,但为了可测试性,我必须创建接口(interface)并将 dataset.WriteXml() 移至其实现,这在我看来是不必要的层并使代码不那么明显。其次 - 如果我将访问文件系统的所有方法移至单个接口(interface),它将违反 SRP 原则,因为序列化\反序列化数据集和从文件读取数据格式似乎是不同的责任,对吗?
最佳答案
我认为你需要进一步拆分你的代码......
你说: 假设我有一个函数
- 将数据从数据库加载到数据集中,
- 格式化加载的数据(格式存储在某些外部 xml 文件中)和
- 最终将数据集序列化为文件。
听起来至少有 3-4 个工作......
如果您将代码进一步拆分,那么您就可以测试每个函数,而无需围绕它们进行其他所有操作。
如果您只想执行 Dataset.WriteXML,那么您不必测试它。这是一个运行良好的框架功能。尝试在那里添加一些模拟来伪造它。具体如何取决于您的解决方案...
评论答案:
用自己的测试创建所有这些小类将使测试变得容易,并且还将使您的函数变得小而紧凑(->易于测试)您将测试数据集的内容是否正是您所需要的,而不是如果数据集正确序列化为 xml 文件。您还将测试您的格式化程序是否能够正确执行其功能,而不依赖于任何其他逻辑。您还将测试数据访问,但不访问数据库(再次 stub /模拟)
当您知道所有这些都按其应有的方式工作后,您“只需”验证数据集上的正确方法是否会被调用,这应该会让您满意,因为您已经单独测试了其他部分。
单元测试的棘手部分是进行有意义的测试。它们应该是“快速”和“简单”
为了使测试更快,你不应该接触你无法控制的东西:
- 网络服务
- 文件系统
- 数据库
- Com 对象
为了让它们变得简单,你可以让你的类(class)专注于一个任务,这就是你已经提到过的 SRP 的用武之地。看看这个答案...它还会指出“SOLID”开发的其他原则
https://stackoverflow.com/questions/1423597/solid-principles/1423627#1423627
关于unit-testing - 文件访问、单元测试、依赖注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1461016/