BDD/TDD:依赖关系可以是一种行为吗?

BDD/TDD:依赖关系可以是一种行为吗?,tdd,bdd,Tdd,Bdd,我被告知不要使用实现细节。依赖项似乎是一个实现细节。然而,我也可以把它表述为一种行为 示例:链接列表依赖于存储引擎来存储其链接(例如LinkStorageInterface)。构造函数需要被传递一个已实现的LinkStorageInterface实例才能完成其工作。 我不能说“应该使用链接存储”。但也许我可以说“应该存储链接存储” 在这种情况下,“测试”什么是正确的?我应该测试它是否将链接存储在存储中(行为),还是根本不测试它?LinkStorageInterface不是一个实现细节,它的名称表

我被告知不要使用实现细节。依赖项似乎是一个实现细节。然而,我也可以把它表述为一种行为

示例:链接列表依赖于存储引擎来存储其链接(例如LinkStorageInterface)。构造函数需要被传递一个已实现的LinkStorageInterface实例才能完成其工作。 我不能说“应该使用链接存储”。但也许我可以说“应该存储链接存储”


在这种情况下,“测试”什么是正确的?我应该测试它是否将链接存储在存储中(行为),还是根本不测试它?

LinkStorageInterface不是一个实现细节,它的名称表示一个引擎接口。在这种情况下,名称shouldUseLinkStorage的值大于shouldStoreLinksInStorage的值


那是我的两便士

依赖项本身不是预期的行为,但对依赖项调用的操作肯定是。你应该测试你(调用者)知道的东西,避免测试那些需要你熟悉SUT内部工作原理的东西

稍微扩展一下您的示例,让我们假设我们的LinkStorageInterface具有以下定义(伪代码):

现在,由于您(调用者)正在为该接口提供具体的实现,因此测试
writeListPersistentMedium()
在调用
LinkList
上的
Save()
方法时被调用是完全合理的

测试可能是这样的,同样使用伪代码:

void ShouldSaveLinkListToPersistentMedium()

  define da = new MockLinkListStorage()  
  define list = new LinkList(da)

  list.Save()

  Assert.Method(da.WriteListToPersistentMedium).WasCalledWith(list)

end method
您已经测试了预期行为,但没有测试SUT或模拟的特定于实现的细节。您希望避免(主要)测试的是:

  • 调用方法的顺序
  • 将方法或属性设置为公共以便可以检查
  • 任何不直接涉及您正在测试的预期行为的内容

  • 同样,依赖项是您作为类的使用者提供的,因此您希望使用它。否则,从一开始就没有必要有这种依赖性。

    你是在问考试题目还是如何编写考试?看来你已经越来越深入地盯着肚脐了,也就是“元”。我建议回到一些基本的敏捷原则,比如“做可能工作的最简单的事情”,问问自己为什么需要将链接存储机制与LinkedList分开。@Josh你认为测试具有某些行为的无效方法是一种好的做法吗?e、 通过在模拟上调用Verify?因为在方法中没有返回任何内容。@User101-是。这是基于交互的测试和基于状态的测试之间的区别。不管方法的返回类型如何,您可能仍然希望测试它与依赖项之间的一些交互。依赖项可以是模拟的。。。你真的不在乎。重要的是代码如何响应各种可控行为或依赖关系。“如果它返回null会发生什么?”“如果它抛出异常会发生什么?”等等@Josh感谢这对于行为来说是有意义的,如果类将一个dto映射到另一个dto,然后用新的dto调用外部接口,那么整个方法仍然会返回一个void。通过验证用新dto调用模拟接口一次,是否值得测试映射是否正确发生?
    void ShouldSaveLinkListToPersistentMedium()
    
      define da = new MockLinkListStorage()  
      define list = new LinkList(da)
    
      list.Save()
    
      Assert.Method(da.WriteListToPersistentMedium).WasCalledWith(list)
    
    end method