phpunit9模拟方法仍在执行

发布于 2025-02-09 00:37:46 字数 2361 浏览 0 评论 0原文

我正在尝试嘲笑打电话给Twilio Rest API进行我写的测试。这是我编写要模拟的代码:

$message = $twilioTest->getMockedMessageInstance(['body' => 'This won\'t exist']);
$twilioStub = $this->getMockBuilder(Twilio::class)->getMock();
$twilioStub->expects($this->once())->method('retrieveLastTextFromBot')->willReturn($message);

retievelastTextFrombot方法的内容是:

$messages = $this->twilioClient->messages->read([
    'to' => TwilioDefinitions::getToNumber(),
    'from' => getenv('TWILIO_NUMBER'),
], 1);
if (count($messages) !== 1) {
     throw new NoExtantTextException('No previous message from ' . getenv('TWILIO_NUMBER') . ' to ' . TwilioDefinitions::getToNumber());
}
return $messages[0];

但是,显然,我不希望retievelastTextTextFrombot methode ,这就是为什么我嘲笑它。不过,由于某些原因,该方法正在执行,我知道,因为在我的phpunit失败中,我会遇到此错误:

1) CronControllerTest::testRemindMethodErrorHandling
Twilio\Exceptions\RestException: [HTTP 403] Unable to fetch page: Resource not accessible with Test Account Credentials

/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Page.php:58
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Page.php:34
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/MessagePage.php:23
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/MessageList.php:147
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/MessageList.php:96
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/MessageList.php:118
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/app/YmcaScheduler/Utility/Twilio.php:33
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/app/YmcaScheduler/Controller/CronController.php:29
/Users/adammcgurk/Desktop/ymca-scheduler-brains/tests/CronControllerTest.php:22

twilio.php中的第33行是RETRIEVELASTTEXTTEXTFROMBOT()方法的第四行,所以它正在执行。

也许我只是不正确地理解嘲笑,但是我认为会发生的事情是根本不会执行该方法,而是phpunit只会强迫数据返回。

我如何在不实际执行的情况下模拟Phpunit的方法?

I'm trying to mock a call to the Twilio Rest API for a test I'm writing. This is the code I've written to mock:

$message = $twilioTest->getMockedMessageInstance(['body' => 'This won\'t exist']);
$twilioStub = $this->getMockBuilder(Twilio::class)->getMock();
$twilioStub->expects($this->once())->method('retrieveLastTextFromBot')->willReturn($message);

And the contents of the retrieveLastTextFromBot method are:

$messages = $this->twilioClient->messages->read([
    'to' => TwilioDefinitions::getToNumber(),
    'from' => getenv('TWILIO_NUMBER'),
], 1);
if (count($messages) !== 1) {
     throw new NoExtantTextException('No previous message from ' . getenv('TWILIO_NUMBER') . ' to ' . TwilioDefinitions::getToNumber());
}
return $messages[0];

But obviously, I don't want the contents of the retrieveLastTextFromBot method to execute, that's why I'm mocking it. For some reasons though, that method is executing, and I know that because in my phpunit failure I'm getting this error:

1) CronControllerTest::testRemindMethodErrorHandling
Twilio\Exceptions\RestException: [HTTP 403] Unable to fetch page: Resource not accessible with Test Account Credentials

/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Page.php:58
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Page.php:34
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/MessagePage.php:23
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/MessageList.php:147
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/MessageList.php:96
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/MessageList.php:118
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/app/YmcaScheduler/Utility/Twilio.php:33
/Users/adammcgurk/Desktop/ymca-scheduler-brains/src/app/YmcaScheduler/Controller/CronController.php:29
/Users/adammcgurk/Desktop/ymca-scheduler-brains/tests/CronControllerTest.php:22

And line 33 in Twilio.php is that fourth line of the retrieveLastTextFromBot() method, so it's executing.

And maybe I just understand mocking incorrectly, but what I thought was going to happen was the method wouldn't be executed at all, instead, phpunit would just force data to be returned from it.

How can I mock a method in phpunit without it actually being executed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

在巴黎塔顶看东京樱花 2025-02-16 00:37:46

工作示例

我以一个工作示例开始这个答案。您可以按照此答案中的解释进行两件事。当答案的部分适合您的情况时,请使用额外的信息/详细信息更新您的问题。

将此代码添加到tests/twiliotest.php

<?php 

use PHPUnit\Framework\TestCase;
use Twilio\Rest\Client;

class Twilio
{
    private $twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->twilioClient = $twilioClient;
    }

    public function retrieveLastTextFromBot()
    {
        $messages = $this->twilioClient->messages->read([
            'to' => TwilioDefinitions::getToNumber(),
            'from' => getenv('TWILIO_NUMBER'),
        ], 1);
        if (count($messages) !== 1) {
             throw new NoExtantTextException('No previous message from ' . getenv('TWILIO_NUMBER') . ' to ' . TwilioDefinitions::getToNumber());
        }
        return $messages[0];
    }
}

class Sut
{
    private $twilio;
    public function __construct(Twilio $twilio)
    {
        $this->twilio = $twilio;
    }

    public function method()
    {
        $this->twilio->retrieveLastTextFromBot();
    }
}

final class TwilioTest extends TestCase
{
    //I created a plain php object for the message just for the example 
    private function getMockedMessageInstance(array $message)
    {
        return (object) $message;
    }

    public function test_sut_method(): void
    {
$message = $this->getMockedMessageInstance(['body' => 'This won\'t exist']);
        $twilioStub = $this
            ->getMockBuilder(Twilio::class)
            ->disableOriginalConstructor() # I have added this to ignore the Twilio constructor dependencies
            ->getMock();
        $twilioStub->expects($this->once())->method('retrieveLastTextFromBot')->willReturn($message);
        
        $sut = new Sut($twilioStub);
        $result = $sut->method();
    }
}

结果

执行测试:

vendor/bin/phpunit tests/

请验证此代码是否也适用于您。如果没有,请告诉我您使用哪些作曲家库版本。考虑将此信息添加到您的问题Composer Show -I

结果应该是:

PHPUnit 9.5.21 #StandWithUkraine

.                                                                   1 / 1 (100%)

Time: 00:00.006, Memory: 4.00 MB

OK (1 test, 1 assertion)

我希望您以某种方式调用retievelastTextFrombot在其他内容上,模拟对象

如果上述代码工作,我怀疑您以某种方式调用方法retrievelastTextFrombot在生产代码上,而不是模拟对象,或者您可以从其他位置执行两次方法。

要找出真正发生的事情,将以下代码添加到RETIEVELASTTEXTFROMBOT(在您的生产代码中):

public function retrieveLastTextFromBot()
{
    var_dump(debug_backtrace()[0]['file']); # This line
    var_dump(debug_backtrace()[0]['line']); # This line
    exit; # This line

    $messages = $this->twilioClient->messages->read([
        'to' => TwilioDefinitions::getToNumber(),
        'from' => getenv('TWILIO_NUMBER'),
    ], 1);
    if (count($messages) !== 1) {
         throw new NoExtantTextException('No previous message from ' . getenv('TWILIO_NUMBER') . ' to ' . TwilioDefinitions::getToNumber());
    }
    return $messages[0];
}

如果它返回sut> sut(系统正在测试的系统)的文件,则现在,您确定您没有在模拟对象上执行该方法。您可能会看到一个不同的文件,在这种情况下,检查您的代码以查看您执行的位置。

检查您的测试以查看构造函数中传递的实例。如果否则,请让我知道debug_backtrace()的结果是什么,并考虑使用结果更新您的问题,以便我们继续提供帮助,因为并非所有代码都可能需要所有代码来帮助您更远。

如果以前的解释测试中没有提供足够的信息,请考虑使用您的代码暂时添加GitHub存储库,并在可能的情况下进行一些测试环境凭据。

Working example

I start this answer with a working example. There are two things you can check as explained in this answer. Please update your question with extra information/ details when parts of the answer fit your situation.

Add this code to tests/TwilioTest.php:

<?php 

use PHPUnit\Framework\TestCase;
use Twilio\Rest\Client;

class Twilio
{
    private $twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->twilioClient = $twilioClient;
    }

    public function retrieveLastTextFromBot()
    {
        $messages = $this->twilioClient->messages->read([
            'to' => TwilioDefinitions::getToNumber(),
            'from' => getenv('TWILIO_NUMBER'),
        ], 1);
        if (count($messages) !== 1) {
             throw new NoExtantTextException('No previous message from ' . getenv('TWILIO_NUMBER') . ' to ' . TwilioDefinitions::getToNumber());
        }
        return $messages[0];
    }
}

class Sut
{
    private $twilio;
    public function __construct(Twilio $twilio)
    {
        $this->twilio = $twilio;
    }

    public function method()
    {
        $this->twilio->retrieveLastTextFromBot();
    }
}

final class TwilioTest extends TestCase
{
    //I created a plain php object for the message just for the example 
    private function getMockedMessageInstance(array $message)
    {
        return (object) $message;
    }

    public function test_sut_method(): void
    {
$message = $this->getMockedMessageInstance(['body' => 'This won\'t exist']);
        $twilioStub = $this
            ->getMockBuilder(Twilio::class)
            ->disableOriginalConstructor() # I have added this to ignore the Twilio constructor dependencies
            ->getMock();
        $twilioStub->expects($this->once())->method('retrieveLastTextFromBot')->willReturn($message);
        
        $sut = new Sut($twilioStub);
        $result = $sut->method();
    }
}

Result

Execute the tests:

vendor/bin/phpunit tests/

Please verify if this code is working for you also. If not, please tell me what composer library versions you use. Consider adding this info to your question composer show -i.

The result should be:

PHPUnit 9.5.21 #StandWithUkraine

.                                                                   1 / 1 (100%)

Time: 00:00.006, Memory: 4.00 MB

OK (1 test, 1 assertion)

I expect you somehow call retrieveLastTextFromBot on something else than the mock object

If the code above is working, I suspect you somehow call the method retrieveLastTextFromBot on the production code, instead of the mock object or you might execute the method twice from a different location.

To find out what is really happening add the following code to retrieveLastTextFromBot (in your production code):

public function retrieveLastTextFromBot()
{
    var_dump(debug_backtrace()[0]['file']); # This line
    var_dump(debug_backtrace()[0]['line']); # This line
    exit; # This line

    $messages = $this->twilioClient->messages->read([
        'to' => TwilioDefinitions::getToNumber(),
        'from' => getenv('TWILIO_NUMBER'),
    ], 1);
    if (count($messages) !== 1) {
         throw new NoExtantTextException('No previous message from ' . getenv('TWILIO_NUMBER') . ' to ' . TwilioDefinitions::getToNumber());
    }
    return $messages[0];
}

If it returns the file where the SUT (System under test) is located, you now know for sure you don't have executed the method on the mock object. You might see a different file, in that case, check your code to see from where you execute it.

Check your tests to see what instance is passed in the constructor. If otherwise, let me know what the result of the debug_backtrace() is and consider updating your question with the results so we can continue to help, since not all code is provided it might be needed to help your further.

If non of the previous explained tests gave you enough information, please consider adding a temporarily github repository with your code and maybe if possible some test environment credentials.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文