|
|
1
3
解决问题的一个方法是将控制器更改为按需
在您的实际应用程序中,让您的IOC容器注入
(见) Misko Hevry's article about constructors doing real work 有关像这样重新构造代码的好处的扩展讨论。) |
|
|
2
2
就个人而言,我将围绕引用存储库的工作模式单元设计系统。这可以使事情简单得多,并允许原子地运行更复杂的操作。你通常会有一个
如果我理解正确的话,您会担心一段(低级别)代码中的错误会导致大量测试失败,从而使您很难看到实际的问题。你采取
虽然你的担心是正确的,但我个人不会担心失败
服务导致的控制器错误是另一杯茶IMO。虽然您可以模拟服务,但这会使测试变得更困难,并且不可信。最好不要测试服务。只测试控制器!控制器将调用服务,如果您的服务表现不好,您的控制器测试将发现。这样,您只测试应用程序中的顶级对象。代码覆盖率将帮助您识别不测试的代码部分。当然,这在所有场景中都是不可能的,但这通常很有效。当服务与模拟存储库(或工作单元)一起工作时,这将非常有效。 你的第二个问题 是因为这些经历让你 大量测试设置 . 我有两件事要说。 首先,我尽量将依赖性倒置最小化到只需要能够运行单元测试的程度。应伪造对系统时钟、数据库、SMTP服务器和文件系统的调用,以使单元测试快速可靠。其他的事情我尽量不颠倒,因为你越是嘲笑,测试就越不可靠。你的测试更少了。最小化依赖倒置(达到你需要的好 RTM 单元测试)有助于简化测试设置。 但是(第二点),您还需要以可读性和可维护性的方式编写单元测试(关于单元测试的困难部分,或者实际上是一般的软件制作)。拥有大的测试设置会使它们难以理解,并且当类获得新的依赖关系时,测试代码很难更改。我发现,使测试更具可读性和可维护性的最佳方法之一是在测试类中使用简单的工厂方法来集中创建测试中需要的类型(我从不使用模拟框架)。我使用两种模式。一种是简单的工厂方法,例如创建有效类型的方法:
这样测试就可以简单地调用这些方法,当它们需要一个有效的对象时,只需调用一个工厂方法。当然,当这些方法中的一个意外地创建了一个无效对象时,许多测试都将失败。这很难阻止,但很容易解决。容易修复意味着测试是可维护的。 我使用的另一种模式是使用一个容器类型,它保存了您要创建的实际对象的参数/属性。当一个对象有许多不同的属性和/或构造函数参数时,这一点尤其有用。将它与容器的工厂和要创建的对象的生成器方法混合,您将得到非常可读的测试代码:
这允许您让测试只指定重要的内容!这对于使测试可读非常重要!这个
你的第三个问题 是关于不能 测试LINQ查询 对给定的LINQ提供程序有预期的行为。这是一个有效的问题,因为编写LINQ(to Expression Tree)查询非常容易,当在内存中对象上使用时,这些查询运行得很好,但在查询数据库时失败。有时无法转换查询(因为您调用的.NET方法在数据库中没有对应项),或者LINQ提供程序有限制(或错误)。尤其是实体框架3.5的LINQ提供者很差劲。 但是,这是一个您不能用每个定义的单元测试来解决的问题。因为当您在测试中调用数据库时,它不再是单元测试了。但是,单元测试永远不会完全取代手动测试:—)
不过,这是一个值得关注的问题。除了单元测试之外,您还可以进行集成测试。在这种情况下,您可以使用真正的提供者和(专用的)测试数据库来运行代码。在数据库事务中运行每个测试,并在测试结束时回滚该事务。(
TransactionScope
用这个很好!)但是请注意,编写可维护的集成测试比编写可维护的单元测试更困难。您必须确保测试数据库的模型是同步的。每个集成测试都应该将测试所需的数据插入到数据库中,这通常是需要编写和维护的大量工作。最好是将集成测试的数量保持在最低限度。有足够的集成测试,使您对系统的更改充满信心。例如,在单个测试中调用带有复杂LINQ语句的服务方法通常足以测试您的LINQ提供程序是否能够从中构建有效的SQL。大多数情况下,我只是假设Linq提供程序将具有与LinqTo对象相同的行为。(
我希望这有帮助。 |
|
|
3
1
我认为您的方法对于测试服务层本身是合理的,但是,正如您所建议的那样,如果服务层完全模拟为您的业务逻辑和其他高级测试,那就更好了。这使得更高级别的测试更容易实现/维护,因为如果已经测试了服务层,就不需要再次运行它了。 |
|
|
Andrus · 如何在Linux中阅读期刊 1 年前 |
|
|
Miranda · 读取xml文件时路径错误中有非法字符 1 年前 |
|
|
Primdonm · 如何将自定义列表中的字符串值格式化为货币格式? 2 年前 |
|
|
Kiryl · Sitecore中自己的控制器 2 年前 |
|
|
Farid · 如何从数据库中填充Resource.resx文件值? 2 年前 |