Unit testing 单元测试应该针对RESTAPI进行测试吗?

Unit testing 单元测试应该针对RESTAPI进行测试吗?,unit-testing,testing,Unit Testing,Testing,有一段时间,我已经将我的业务逻辑与RESTAPI层分开进行了单元测试。 在集成测试中,我根据服务的api测试了服务本身 当然,集成测试并不包括单元测试包含的所有边缘情况。它感觉像是一个过度杀戮和重复的测试代码 但事实上,我只剩下一整层没有被覆盖。我不能确定返回值是否按预期序列化,错误代码是否正确,或者参数是否按我的要求反序列化 我的问题是,我是否应该放弃通过实现它们的对象测试业务逻辑,而通过服务进行测试,以便在不重复工作的情况下合并所有案例 注意事项: 我不是说放弃所有的单元测试。不直接接触A

有一段时间,我已经将我的业务逻辑与RESTAPI层分开进行了单元测试。
在集成测试中,我根据服务的api测试了服务本身

当然,集成测试并不包括单元测试包含的所有边缘情况。它感觉像是一个过度杀戮和重复的测试代码

但事实上,我只剩下一整层没有被覆盖。我不能确定返回值是否按预期序列化,错误代码是否正确,或者参数是否按我的要求反序列化

我的问题是,我是否应该放弃通过实现它们的对象测试业务逻辑,而通过服务进行测试,以便在不重复工作的情况下合并所有案例

注意事项:

  • 我不是说放弃所有的单元测试。不直接接触API层的足够复杂的单元仍应单独测试
  • 测试运行时在这里不是问题
更新 添加了一些示例伪代码以澄清

class Book:
  id: int
  title: string


class BookRepository:
  add_book(book: Book) -> Book
  remove_book(id: int) -> bool
  all() -> List[Book]


class BookApi:
  repository = BookRepository()

  @route('/api/books')
  get() -> List[Book]

  @route('/api/books/id', method=POST)
  add(request_body) -> bool :
    book = parse_book_from_request(request_body)
    return repository.add(book)

  @route('/api/books/id', method=DELETE)
  delete() -> bool


根据你的描述,我看到的情况如下:

您有两个单元测试场景,即业务逻辑的单元测试和REST层的单元测试。您还有一个交互测试场景,即REST层和业务逻辑之间的交互。并且,您有一个子系统测试场景,即测试由REST层和业务逻辑组成的子系统

而且,您还担心解决所有这些测试场景可能会带来的工作量和潜在冗余。(事实上,您只提到了业务逻辑单元测试和集成测试,所以我可能会让它更糟一些…)

这里可以帮助您的是,针对这些测试场景中的每一个,问问您自己,还有哪些其他测试尚未解决的bug可能仍然存在。如果您想到一个测试用例,但是您想不出测试可能检测到的任何bug,那么可能不需要该测试用例,或者它的目的已经用另一种方式解决了

自下而上:您有业务逻辑的单元测试。那么,什么单元测试对REST层有意义呢?您提到了反序列化,但也可能存在合理性检查和对格式错误请求的处理。所有这些都需要彻底的测试——包括出于安全原因的负面测试。想想在隔离的REST层中可以发现的bug——这些bug显然不是通过隔离业务逻辑的单元测试发现的

现在,进入交互测试(也称为集成测试):这些测试的目标只是各个部分之间的交互,而不是任何一方是否在之后做了正确的事情(这是通过单元测试测试的)。换句话说,测试检查是否以正确的顺序和正确的格式使用参数调用正确的函数,或者更一般地说,如果接口双方都有相同的理解。边界情况在这里也有意义——例如,看看被调用方是否能够处理调用方提供的极端情况。诚然,如果组件之间的接口与组件大小相比较大,则存在冗余风险

但是,您可以通过某些方式限制冗余:假设您的REST层设计用于过滤无效的
book\u id
值。您需要测试REST层将传递的最大的
book\u id
是否被业务逻辑接受。如果业务逻辑本身检查
book\u id
,如果不接受,则抛出异常,那么您的交互测试可以关注是否抛出异常。您不必验证是否找到了正确的书籍——这是在对业务逻辑进行单元测试时测试的

然后,子系统测试:再次,考虑哪些bug可能没有被捕获,而这些bug只能在整个子系统中找到。例如,子系统是否满足所有需求,或者是否忘记了某些功能?(单元测试不会发现被遗忘的特性,交互测试可能——但不是在所有情况下。)是否存在测试可以识别的版本不匹配?并且,再次尝试将测试集中在基本方面,以避免单元和交互测试的冗余


很抱歉,我只能给出一些抽象的建议和抽象的示例。

您能为这两部分(业务代码和REST Api)提供一些代码示例吗?@DirkHerrmann我添加了一个简单的示例来说明分离。我希望这是清楚的。Api负责解析请求,而不是业务逻辑。谢谢,这是我所期望的抽象答案,非常好。我想我对每次考试都有一个想法。我可以使用json对象测试REST层,并验证输入是否正确发送到业务对象。在测试业务逻辑时,我可以使用对象及其不同的边缘情况来测试逻辑本身。