根据对象属性值,PHPunit对连续调用的模拟对象和响应的方式不同

时间:2017-06-22 08:51:01

标签: php phpunit

我正在嘲笑一个类的函数,并尝试根据给定对象(该模拟函数的参数)作为属性返回不同的值。

在我的代码下面,有一些评论:

  • 我嘲笑FacebookHelper类
  • 我对getExternalCampaignData(Campaign $ campaign)函数感兴趣,所以我“操纵”它到
  • 我想根据广告系列ID
  • 更改返回值
  • PHP:7.0.18& PHPunit版本:5.7.20

代码     

use AppBundle\Entity\Campaign;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;

class FacebookHelperTest extends TestCase {
    public function testIfStatusSyncIsSetCorrectly() {
        $campaign = new Campaign();

        /** @var \PHPUnit_Framework_MockObject_MockObject|Logger $logger */
        $logger = $this->createMock(Logger::class);

        /** @var \PHPUnit_Framework_MockObject_MockObject|FacebookHelper $helper */
        $builder = $this->getMockBuilder(FacebookHelper::class)->disableOriginalConstructor()->setMethods(['getExternalCampaignData']);
        $helper = $builder->getMock();

        $helper->expects($this->exactly(3))
            ->method('getExternalCampaignData')
            ->withConsecutive(
                [$this->callback(function(Campaign $campaign) { var_dump($campaign->getFbCampaignId(), "expecting 1"); return $campaign->getFbCampaignId() == 1; })],
                [$this->callback(function(Campaign $campaign) { var_dump($campaign->getFbCampaignId(), "expecting 2"); return $campaign->getFbCampaignId() == 2; })],
                [$this->callback(function(Campaign $campaign) { var_dump($campaign->getFbCampaignId(), "expecting 3"); return $campaign->getFbCampaignId() == 3; })]
            )
            ->willReturnOnConsecutiveCalls(
                ['campaign' => ['status' => FacebookHelper::CAMPAIGN_STATUS_ACTIVE]],
                ['campaign' => ['status' => FacebookHelper::CAMPAIGN_STATUS_ACTIVE]],
                ['campaign' => ['status' => FacebookHelper::CAMPAIGN_STATUS_ARCHIVED]]
            );

        $campaign->setFbCampaignId(1);
        $campaign->setStatus('active');

        $modifiedCampaign = $helper->modifyCampaignIfNeeded($campaign, $logger);
        $this->assertFalse($modifiedCampaign->getSettings('fb_status_out_of_sync'));

        $campaign->setFbCampaignId(2);
        $campaign->setStatus('paused');

        $modifiedCampaign = $helper->modifyCampaignIfNeeded($campaign, $logger);
        $this->assertTrue($modifiedCampaign->getSettings('fb_status_out_of_sync'));

        $campaign->setFbCampaignId(3);
        $campaign->setStatus('paused');

        $modifiedCampaign = $helper->modifyCampaignIfNeeded($campaign, $logger);
        $this->assertTrue($modifiedCampaign->getSettings('fb_status_out_of_sync'));
    }
}

当我进行上述单元测试时,一切似乎都正常。 除了某种行为有点奇怪之外,回调被调用了太多次。

我已经发现了一个可能导致这种情况的错误:https://github.com/sebastianbergmann/phpunit-mock-objects/issues/261 因此我将phpunit更新到5.7.20版本以希望此问题得到修复

或许我需要使用不同的方法?

PHPunit的结果

Testing started at 10:40 AM ...
Nothing to update - your database is already in sync with the current entity metadata.
PHPUnit 5.7.20 by Sebastian Bergmann and contributors.


Expectation failed for method name is equal to <string:getExternalCampaignData> when invoked 3 time(s)
Parameter 0 for invocation #0 AppBundle\Services\FacebookHelper::getExternalCampaignData(AppBundle\Entity\Campaign Object (...)) does not match expected value.
Failed asserting that AppBundle\Entity\Campaign Object &0000000026aee99e00000000359c8973 (
    ...
    'status' => 'paused'
    ...
    'fb_campaign_id' => 2
    ...
    'settings' => Array &1 (
        'fb_status_out_of_sync' => false
    )
    ...
) is accepted by specified callback.
 /home/ali/www/src/AppBundle/Services/FacebookHelper.php:1227
 /home/ali/www/tests/AppBundle/Services/FacebookHelperTest.php:41

int(1)
string(11) "expecting 1"
int(1)
string(11) "expecting 1"
int(2)
string(11) "expecting 2"
int(2)
string(11) "expecting 1"


Time: 702 ms, Memory: 6.00MB


FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

Process finished with exit code 1

2 个答案:

答案 0 :(得分:0)

Oke,经过大量的搜索,我检查了phpunit测试本身的单元测试(悖论:p?),最后发现它是如何工作的。

解决方案

$helper->expects($this->exactly(3))
            ->method('getExternalCampaignData')
            ->will(
                $this->returnCallback(
                    function(Campaign $campaign) {
                        if($campaign->getFbCampaignId() == 1) return ['campaign' => ['status' => FacebookHelper::CAMPAIGN_STATUS_ACTIVE]];
                        if($campaign->getFbCampaignId() == 2) return ['campaign' => ['status' => FacebookHelper::CAMPAIGN_STATUS_ACTIVE]];
                        if($campaign->getFbCampaignId() == 3) return ['campaign' => ['status' => FacebookHelper::CAMPAIGN_STATUS_ARCHIVED]];
                    }
                )
            );

答案 1 :(得分:0)

您可以将此简化为

# set the initial size
from kivy.config import Config

MAX_SIZE = (300, 150)
Config.set('graphics', 'width', MAX_SIZE[0])
Config.set('graphics', 'height', MAX_SIZE[1])

from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window


class My(App):
    def check_resize(self, instance, x, y):
        # resize X
        if x > MAX_SIZE[0]:
            Window.size = (300, Window.size[1])
        # resize Y
        if y > MAX_SIZE[1]:
            Window.size = (Window.size[0], 150)

    def build(self):
        Window.bind(on_resize=self.check_resize)
        return Button()

My().run()