【问题标题】:Integration Test Assertion Best Practice集成测试断言最佳实践
【发布时间】:2021-09-03 06:29:45
【问题描述】:

我最近在我的旧应用上实现了集成测试,我对在集成测试中进行断言感到困惑。

在单元测试中,我们可以轻松地模拟对象,并且每次测试只有 1 个断言是有意义的。但是当它变成集成测试时,我想验证多个场景,需要检查每一步是否正确。

可以做多个断言吗?还是有一些最佳做法可以做到这一点?

这是我的测试代码:

   def test_new_requested_depth_purchase_create_transaction(
        self,
        requested_depth_purchase_request_1: DepthPurchaseRequestViewModel,
    ):
        """depth_purchase_created_job() should create new lead,transaction and depth transaction package"""

        self._depth_purchase_request_service.depth_purchase_created_job(
            requested_depth_purchase_request_1.original_id
        )

        crm_depth_purchase = self._depth_purchase_repo.get_by_original_id(
            requested_depth_purchase_request_1.original_id
        )
        assert crm_depth_purchase is not None

        lead = self._lead_repo.get_by_id(crm_depth_purchase.leads_id)

        assert lead is not None

        transaction = self._transaction_repo.get_by_lead_id(lead.id)

        assert transaction is not None

        transaction_packages = self._transaction_package_repo.get_all_by_transaction_id(
            transaction.id
        )

        assert len(transaction_packages) > 0
        assert all(
            [
                trx_package.type == ProductPackageConstants.ALACARTE
                and trx_package.status_id == 0
                for trx_package in transaction_packages
            ]
        )

测试框架:Pytest

【问题讨论】:

    标签: python pytest integration-testing


    【解决方案1】:

    是或否,这取决于。 “集成测试”这个名字定义不清,有很多重叠的含义。
    定义极端更简单:单元测试通常只有一个断言,而端到端测试有很多。考虑到这一点,有充分的理由更喜欢拥有多个断言还是只有一个。

    另一种回答问题的方法是基于代码架构“Given-When-Then”。我可以像这样重新组织你的代码:

    def test_new_requested_depth_purchase_create_transaction(
        self,
        requested_depth_purchase_request_1: DepthPurchaseRequestViewModel,
    ):
        """depth_purchase_created_job() should create new lead,transaction and depth transaction package"""
        # When
        self._depth_purchase_request_service.depth_purchase_created_job(
            requested_depth_purchase_request_1.original_id
        )
    
        # Then
        crm_depth_purchase = self._depth_purchase_repo.get_by_original_id(
            requested_depth_purchase_request_1.original_id
        )
        assert crm_depth_purchase is not None
    
        lead = self._lead_repo.get_by_id(crm_depth_purchase.leads_id)
        assert lead is not None
    
        transaction = self._transaction_repo.get_by_lead_id(lead.id)
        assert transaction is not None
    
        transaction_packages = self._transaction_package_repo.get_all_by_transaction_id(
            transaction.id
        )
        assert len(transaction_packages) > 0
        assert all(
            [
                trx_package.type == ProductPackageConstants.ALACARTE
                and trx_package.status_id == 0
                for trx_package in transaction_packages
            ]
        )
    

    没有“Given”,因为它由夹具requested_depth_purchase_request_1 处理。如果模型未注入,则必须创建它,这会导致类似:

    def test_new_requested_depth_purchase_create_transaction(self):
        # Given
        requested_depth_purchase_request_1 = some_way_to_construct_it().maybe_in_several_steps()
        
        # When
        ...
    

    theory 中,您不应该在 Given 和 When 中使用断言(您的测试代码应该可以正常工作),只在 Then 中使用断言,因为这是测试的目的。但它可以作为健全性检查。

    对我来说,你做的很好。做适合您(或您的团队)的事情。

    【讨论】:

    • Given, When, Then,听起来像 BDD。如果出现故障,发现错误会有问题吗?
    • @FarisDewantoro BDD 远不止这些:您应该提前为任何功能代码编写验收测试,并且它们应该是可执行的(参见 Gherkin+Cucumber)。在这里,我们只是构建测试以清楚地概述其目的是什么(已经存在于 docstring 中),这有助于验证所有断言是否相关。我的意思是,如果您有几件事要检查(leadtransactionpackages),那么都属于 Then,并且可以有多个断言。但是如果你愿意,你可以将你的测试分成三部分,没有更好的明确解决方案,这取决于。
    • 但是如果我分成3个,它会干吗?因为要验证我需要获得线索的交易,等等
    • 在这种情况下,我会说最好将所有相关的断言放在一起。但是如果有 10 个断言,也许它应该被拆分。使用夹具,在我看来,分成 3 会是 DRY,不亚于您当前的示例。
    • 最后一个问题顺便说一句,拆分断言有什么好处?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 2016-04-04
    • 2010-10-30
    • 1970-01-01
    • 2010-11-16
    相关资源
    最近更新 更多