代码覆盖 phpunit 测试问题

Posted

技术标签:

【中文标题】代码覆盖 phpunit 测试问题【英文标题】:Codecoverage phpunit test issue 【发布时间】:2021-02-08 13:10:02 【问题描述】:

我正在运行 phpunit 9.2 版,我想知道为什么我的方法不在 phpunit 覆盖范围内。

这是我的课:

class Methods extends Template


    const DISABLED_PAYMENT_METHODS_1 = 'free';
    const DISABLED_PAYMENT_METHODS_2 = 'adyen_cc';
    const DISABLED_PAYMENT_METHODS_3 = 'adyen_oneclick';

    protected $paymentMethodList;

    protected $storeManager;

    protected $logger;

    public function __construct(
        Context $context,
        PaymentMethodList $paymentMethodList,
        StoreManagerInterface $storeManager,
        LoggerInterface $logger,
        array $data = []
    ) 
        $this->paymentMethodList = $paymentMethodList;
        $this->storeManager = $storeManager;
        $this->logger = $logger;
        parent::__construct($context, $data);
    

    public function getPaymentMethods()
    
        try 
            $storeId = $this->storeManager->getStore()->getId();
            $paymentList = $this->paymentMethodList->getActiveList($storeId);
            $resultPayments = [];

            foreach ($paymentList as $payment) 
                if ($payment->getCode() !== self::DISABLED_PAYMENT_METHODS_1 &&
                    $payment->getCode() !== self::DISABLED_PAYMENT_METHODS_2 &&
                    $payment->getCode() !== self::DISABLED_PAYMENT_METHODS_3
                ) 
                    $resultPayments[] = $payment;
                
            

            return $resultPayments;
         catch (Exception $e) 
            $this->logger->error($e->getMessage());
            return false;
        
    

这是我的测试课:

class MethodsTest extends TestCase


    private $model;


    private function getSimpleMock($originalClassName)
    
        return $this->getMockBuilder($originalClassName)
            ->disableOriginalConstructor()
            ->getMock();
    

    public function setUp() : void
    
        $context = $this->getSimpleMock(Context::class);
        $paymentMethodList = $this->getSimpleMock(PaymentMethodList::class);
        $storeManager = $this->getSimpleMock(StoreManagerInterface::class);
        $logger = $this->getSimpleMock(LoggerInterface::class);

        $this->model = new Methods(
            $context,
            $paymentMethodList,
            $storeManager,
            $logger,
            []
        );
    

    public function testGetPaymentMethods()
    
        $stub = $this->createMock(Methods::class);
        $stub->method('getPaymentMethods')
            ->willReturn([]);
        try 
            $stub->getPaymentMethods();
            $this->fail("Expected exception!");
         catch (\Exception $error) 
            $this->assertEquals("Expected exception!", $error->getMessage());
        
    

当我运行命令以获取覆盖率时。我正进入(状态:

我真的很好奇为什么我的测试没有被覆盖或者至少是异常部分?请你分享你的想法为什么?我该怎么做才能解决这个问题?现在我得到了 29% 的覆盖率,我希望得到至少 60% 的覆盖率。

谢谢

【问题讨论】:

您的测试方法为该方法创建了一个模拟,因此运行的是模拟方法。 【参考方案1】:

在这一行 $stub = $this->createMock(Methods::class); 上,您正在创建 Methods 类的模拟,因此实际上并未测试真正的类。

您将需要使用您在 setUp() 方法中创建的对象,并为您传入的依赖项设置模拟返回(可能将其中一些转换为类属性)。

【讨论】:

好的,但是有什么线索可以在不使用模拟的情况下做到这一点吗?它也是关于依赖注入 嗨@Dezza,谢谢更新你的帖子,但如果你能给我一个链接或一个例子,我该怎么做,我将不胜感激【参考方案2】:

你应该测试真实的类,例如:

public function testGetPaymentMethods()

    // define a payment
    $paymentFreeCode = $this->createMock(Payment::class);
    $paymentFreeCode->method('getcode')
        ->willReturn("free");

    // define a payment
    $payment = $this->createMock(Payment::class);
    $payment->method('getcode')
        ->willReturn("invalid-code");

    $paymentList = [
        $paymentFreeCode,
        $payment,
    ];

    // define a store
    $store = $this->createMock(Store::class);
    $store->method('getId')
        ->willReturn("my-store-id");

    // return store from the store manager
    $this->storeManager->method('getStore')
        ->willReturn(myStore);

    // return the payment list
    $this->paymentMethodList->method('getActiveList')->with("my-store-id")
        ->willReturn($paymentList);

    // call the real class instrumented with mocks
    $paymentMethods = $this->model->getPaymentMethods();

    $this->assertIsArray($paymentMethods);
    $this->assertCount($paymentMethods, 1);

【讨论】:

以上是关于代码覆盖 phpunit 测试问题的主要内容,如果未能解决你的问题,请参考以下文章

如何用PHPUnit生成代码覆盖率报告

phpunit 单元测试之代码覆盖率

xdebug : phpunit 代码覆盖的致命错误

phpunit --path-coverage(分支覆盖)需要 100 倍以上的时间

phpunit随机重启测试

在 phpunit 测试中覆盖 symfony TokenAuthenticator