首先让我说我正在使用遗留代码。所以可以做出一些改变,但不能做出激烈的改变。
我的问题是我有一个“车辆”对象,它很简单,但没有接口或任何东西。这个项目是在TDD真正开始变得更加主流之前创建的。无论如何,我需要添加一种新方法来改变车辆的起步里程。我认为这将是尝试TDD和Mocking的良好开端,因为我是新手。我的问题是我需要创建一个车辆做一些涉及进入数据库的检查。对不起,如果我的问题不是100%明确,那就是我发帖的原因,因为我对Rhino Mocks适合的地方感到困惑(如果我需要的话)。
答案 0 :(得分:2)
问题是依赖性。您的车辆类别取决于数据库。希望与数据库的所有交互都被封装到一个很好的类中,我们将在一秒钟内回复它。当您启动单元测试时,您希望能够在不必关心数据库的情况下测试车辆类。例如,您要检查您的SpeedUp(int x)方法是否确实将总速度提高了x。在这种方法中,它首先要求DB询问其当前速度。这意味着你必须有一个DB来测试!大坝,这听起来不是一个非常快速的测试,也不是可重复的。还有很多设置只是运行测试。
如果我们可以假装数据库,那会不会很棒?这就是模拟的用武之地。我们创建了一个包含所有数据库交互的类的模拟。然后我们设置模拟以响应预先编写的值。因此,例如当我们向DB询问当前速度时,您返回100。
所以现在当我们测试模拟返回100并且我们可以断言SpeedUp(int x)需要100并且向它添加x。
答案 1 :(得分:1)
Rhino模拟只能从接口或抽象类创建模拟,这些模拟不存在您的遗留代码。
TypeMock可以嘲笑任何东西,但不是免费的。
您可以使用Microsoft Moles来嘲笑这些。
但是,您应该考虑到Moles应该是您最后的解决方案,最好通过从业务层抽象数据层来重构代码并使其可测试。
HTH
答案 2 :(得分:0)
是否可以轻松创建Vehicle类型的实例(对象),然后调用您的方法进行测试?如果是,那么你很可能不需要模拟。
但是,如果您的Vehicle类型具有需要执行要测试的操作的依赖项(如数据库访问对象),那么您希望使用模拟数据库访问对象,该对象返回测试的固定值,因为您希望你的单元测试能够快速运行。
Vehicle [depends On>] OwnerRepository [satisfied By] SQLOwnerRepository
所以你引入一个接口(一个OwnerRepository来获取所有者的详细信息,比方说)来分离两者之间的DB Interaction(定义合同)。让你真正的依赖(这里是SQLOwnerRepository)实现这个接口。还要设计代码,以便可以注入依赖关系,例如
public Vehicle (OwnerRepository ownerRepository)
{ _ownerRepository = ownerRepository; // cache in member variable }
现在在测试代码中,
Vehicle [depends On >] OwnerRepository [satisifed By] MockOwnerRepository
您有框架,给定一个接口将创建它的模拟实现(请参阅Rhino / Moq框架)。因此,您不再需要实际的数据库连接来测试您的Vehicle类。 模拟用于抽象耗时/不可控制的依赖关系,以保持您的单元测试快速/可预测。
我建议您阅读“依赖注入”,以便更好地了解使用模拟的时间和原因。
答案 3 :(得分:0)
不能直接回答您的问题。但是值得看看以下内容。
Gabriel Schenker发布了关于在遗留系统中应用TDD的消息。 PTOM – Brownfield development – Making your dependencies explicit
本文介绍了如何使用dependencies explicit
和使用依赖注入。它还告诉我Poor Man’s Dependency Injection
。当只有默认构造函数时,这是必需的。
像
这样的东西 public OrderService() : this(
new OrderRepository(),
new EmailSender(ConfigurationManager.AppSettings["SMTPServer"])
)
本文还涉及为ConfigurationManager
创建一个包装器,以使其可测试。