বিভিন্ন যুক্তি সহ phpunit মোক পদ্ধতি একাধিক কল


117

বিভিন্ন ইনপুট আর্গুমেন্টের জন্য বিভিন্ন মক-এক্সপেক্টগুলি সংজ্ঞায়িত করার কোনও উপায় আছে কি? উদাহরণস্বরূপ, আমার কাছে ডিবি নামে ডাটাবেস স্তর শ্রেণি রয়েছে। এই শ্রেণীর "কোয়েরি (স্ট্রিং $ ক্যোরি)" নামক পদ্ধতি রয়েছে, সেই পদ্ধতিটি ইনপুটটিতে একটি এসকিউএল কোয়েরি স্ট্রিং নেয়। আমি কি এই শ্রেণীর (ডিবি) জন্য মক তৈরি করতে পারি এবং ইনপুট ক্যোয়ারী স্ট্রিংয়ের উপর নির্ভরশীল বিভিন্ন ক্যোয়ারী পদ্ধতি কলগুলির জন্য আলাদা রিটার্ন মান সেট করতে পারি?


: নীচের উত্তর ছাড়াও, এছাড়াও আপনি পদ্ধতি এই উত্তরটি ব্যবহার করতে পারেন stackoverflow.com/questions/5484602/...
Schleis

আমি এই উত্তর মত stackoverflow.com/a/10964562/614709
yitznewton

উত্তর:


131

(ডিফল্ট অনুসারে) PHPUnit বিদ্রূপকারী গ্রন্থাগার কিনা একটি প্রত্যাশা একমাত্র ভিত্তিক মিল মিলকারীর প্রেরণ উপর নির্ধারণ করে expectsপ্যারামিটার এবং বাধ্যতা প্রেরণ method। এর কারণে, দুটি expectকলগুলি যা কেবলমাত্র যুক্তিগুলির মধ্যে পৃথক হয়ে গেছে withতা ব্যর্থ হবে কারণ উভয়ই মিলবে তবে কেবল একটি প্রত্যাশিত আচরণ বলে যাচাই করবে। প্রকৃত কাজের উদাহরণের পরে প্রজনন কেস দেখুন।


আপনার সমস্যার জন্য আপনার ব্যবহার করতে হবে ->at()বা->will($this->returnCallback( হিসাবে বর্ণিত হয়েছে another question on the subject

উদাহরণ:

<?php

class DB {
    public function Query($sSql) {
        return "";
    }
}

class fooTest extends PHPUnit_Framework_TestCase {


    public function testMock() {

        $mock = $this->getMock('DB', array('Query'));

        $mock
            ->expects($this->exactly(2))
            ->method('Query')
            ->with($this->logicalOr(
                 $this->equalTo('select * from roles'),
                 $this->equalTo('select * from users')
             ))
            ->will($this->returnCallback(array($this, 'myCallback')));

        var_dump($mock->Query("select * from users"));
        var_dump($mock->Query("select * from roles"));
    }

    public function myCallback($foo) {
        return "Called back: $foo";
    }
}

প্রজনন:

phpunit foo.php
PHPUnit 3.5.13 by Sebastian Bergmann.

string(32) "Called back: select * from users"
string(32) "Called back: select * from roles"
.

Time: 0 seconds, Memory: 4.25Mb

OK (1 test, 1 assertion)


() কল দুটি কেন 'দু'জনের কাজ করে তা পুনরুত্পাদন করুন:

<?php

class DB {
    public function Query($sSql) {
        return "";
    }
}

class fooTest extends PHPUnit_Framework_TestCase {


    public function testMock() {

        $mock = $this->getMock('DB', array('Query'));
        $mock
            ->expects($this->once())
            ->method('Query')
            ->with($this->equalTo('select * from users'))
            ->will($this->returnValue(array('fred', 'wilma', 'barney')));

        $mock
            ->expects($this->once())
            ->method('Query')
            ->with($this->equalTo('select * from roles'))
            ->will($this->returnValue(array('admin', 'user')));

        var_dump($mock->Query("select * from users"));
        var_dump($mock->Query("select * from roles"));
    }

}

ফলাফল স্বরূপ

 phpunit foo.php
PHPUnit 3.5.13 by Sebastian Bergmann.

F

Time: 0 seconds, Memory: 4.25Mb

There was 1 failure:

1) fooTest::testMock
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-select * from roles
+select * from users

/home/.../foo.php:27

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

7
আপনার সাহায্যের জন্য ধন্যবাদ! আপনার উত্তরটি আমার সমস্যার সম্পূর্ণ সমাধান করেছে। পিএস কখনও কখনও টিডিডি বিকাশ আমার জন্য ভয়ঙ্কর বলে মনে হয় যখন আমাকে সাধারণ স্থাপত্যের জন্য এত বড় সমাধান ব্যবহার করতে হবে :)
আলেকসি কর্নুশকিন

1
এটি দুর্দান্ত উত্তর, সত্যই আমাকে পিএইচপিউনিট বিদ্রূপ বুঝতে সাহায্য করেছে। ধন্যবাদ !!
স্টিভ বাউমন

আপনি যে আগ্রহী তার চেয়ে অন্য যুক্তিগুলির জন্য আপনাকে ডিফল্ট মান সরবরাহ করার জন্য $this->anything()প্যারামিটারগুলির মধ্যে একটি হিসাবেও ব্যবহার করতে পারেন->logicalOr()
ম্যাটস লিন্ড

2
"-> লজিকাল ওআর ()" দিয়ে আপনি কোনওটিরই উল্লেখ না করে অবাক হচ্ছেন, আপনি নিশ্চয়তা দিবেন না যে (এই ক্ষেত্রে) উভয় আর্গুমেন্ট বলা হয়েছে। সুতরাং এটি সত্যিই সমস্যার সমাধান করে না।
ব্যবহারকারী 3790897

182

at()আপনি যদি এড়াতে পারেন তবে এটি ব্যবহার করা আদর্শ নয় কারণ তাদের ডক্স দাবি করে as

() ম্যাচারের জন্য $ সূচক পরামিতি সূচককে শূন্য থেকে শুরু করে প্রদত্ত মক অবজেক্টের জন্য সমস্ত পদ্ধতিতে অনুরোধ জানায়। এই ম্যাচারটি ব্যবহার করার সময় সতর্কতা অবলম্বন করুন কারণ এটি ভঙ্গুর পরীক্ষার দিকে নিয়ে যেতে পারে যা নির্দিষ্ট প্রয়োগের বিশদটির সাথে খুব ঘনিষ্ঠভাবে আবদ্ধ থাকে।

৪.১ যেহেতু আপনি withConsecutiveযেমন ব্যবহার করতে পারেন ।

$mock->expects($this->exactly(2))
     ->method('set')
     ->withConsecutive(
         [$this->equalTo('foo'), $this->greaterThan(0)],
         [$this->equalTo('bar'), $this->greaterThan(0)]
       );

আপনি যদি টানা কলগুলিতে এটি ফিরতে চান:

  $mock->method('set')
         ->withConsecutive([$argA1, $argA2], [$argB1], [$argC1, $argC2])
         ->willReturnOnConsecutiveCalls($retValueA, $retValueB, $retValueC);

22
২০১ 2016 সালের হিসাবে সেরা উত্তর accepted গৃহীত উত্তরের চেয়ে ভাল।
ম্যাথু হাউসার

এই দুটি ভিন্ন পরামিতিগুলির জন্য আলাদা কিছু কীভাবে ফিরে আসবেন?
লেনিন রাজ রাজাসেকরণ

@ ইমেলেলিন একইভাবে উইল রিটারনঅনসংশ্পল কলগুলি ব্যবহার করে।
xarlymg89

এফওয়াইআই, আমি পিএইচপিউনিট 4.0.০.২০ ব্যবহার করছিলাম এবং ত্রুটি গ্রহণ করছিলাম, সুরকারের সাথে স্ন্যাপে 4..১-তে Fatal error: Call to undefined method PHPUnit_Framework_MockObject_Builder_InvocationMocker::withConsecutive()উন্নীত হয়েছিল এবং এটি কাজ করছে।
কুইকশিফ্টিন

willReturnOnConsecutiveCallsএটা হত্যা করে।
রাফায়েল ব্যারোস

17

আমি যা পেয়েছি তা থেকে, এই সমস্যাটি সমাধানের সর্বোত্তম উপায় হ'ল পিএইচপিউনিটের মান-মানচিত্রের কার্যকারিতা ব্যবহার করে।

পিএইচপিউনিটের ডকুমেন্টেশন থেকে উদাহরণ :

class SomeClass {
    public function doSomething() {}   
}

class StubTest extends \PHPUnit_Framework_TestCase {
    public function testReturnValueMapStub() {

        $mock = $this->getMock('SomeClass');

        // Create a map of arguments to return values.
        $map = array(
          array('a', 'b', 'd'),
          array('e', 'f', 'h')
        );  

        // Configure the mock.
        $mock->expects($this->any())
             ->method('doSomething')
             ->will($this->returnValueMap($map));

        // $mock->doSomething() returns different values depending on
        // the provided arguments.
        $this->assertEquals('d', $stub->doSomething('a', 'b'));
        $this->assertEquals('h', $stub->doSomething('e', 'f'));
    }
}

এই পরীক্ষা পাস। আপনি দেখতে পারেন:

  • যখন ফাংশনটি "a" এবং "b" পরামিতিগুলির সাথে ডাকা হয়, "d" ফিরে আসে
  • "e" এবং "f" পরামিতিগুলির সাথে যখন ফাংশনটি বলা হয়, "h" ফিরে আসে

আমি যা বলতে পারি তা থেকে এই বৈশিষ্ট্যটি পিএইচপিউইনিত ৩.6 এ প্রবর্তিত হয়েছিল , সুতরাং এটি "পুরানো" যথেষ্ট যে এটি কোনও বিকাশ বা মঞ্চ পরিবেশে এবং কোনও ধ্রুবক সংহতকরণ সরঞ্জাম সহ নিরাপদে ব্যবহার করা যেতে পারে।


6

মনে হচ্ছে উপহাস ( https://github.com/padraic/mockery ) এটি সমর্থন করে। আমার ক্ষেত্রে আমি পরীক্ষা করতে চাই যে একটি ডাটাবেসে 2 টি সূচক তৈরি করা হয়েছে:

উপহাস, কাজগুলি:

use Mockery as m;

//...

$coll = m::mock(MongoCollection::class);
$db = m::mock(MongoDB::class);

$db->shouldReceive('selectCollection')->withAnyArgs()->times(1)->andReturn($coll);
$coll->shouldReceive('createIndex')->times(1)->with(['foo' => true]);
$coll->shouldReceive('createIndex')->times(1)->with(['bar' => true], ['unique' => true]);

new MyCollection($db);

পিএইচপিউনিট, এটি ব্যর্থ:

$coll = $this->getMockBuilder(MongoCollection::class)->disableOriginalConstructor()->getMock();
$db  = $this->getMockBuilder(MongoDB::class)->disableOriginalConstructor()->getMock();

$db->expects($this->once())->method('selectCollection')->with($this->anything())->willReturn($coll);
$coll->expects($this->atLeastOnce())->method('createIndex')->with(['foo' => true]);
$coll->expects($this->atLeastOnce())->method('createIndex')->with(['bar' => true], ['unique' => true]);

new MyCollection($db);

বিদ্রূপের একটি সুন্দর সিনট্যাক্স আইএমএইচও রয়েছে। এটি পিএইচপিউইনিটস অন্তর্নির্মিত উপহাসের ক্ষমতা থেকে কম ধীরে ধীরে বলে মনে হয়, তবে ওয়াইএমএমভি।


0

ইন্ট্রো

ঠিক আছে আমি দেখতে পাচ্ছি মজাদারির জন্য একটি সমাধান দেওয়া আছে, সুতরাং আমি মখারি পছন্দ না করায় আমি আপনাকে একটি ভবিষ্যদ্বাণী বিকল্প দিতে যাচ্ছি তবে আমি আপনাকে প্রথমে উপহাস এবং ভবিষ্যদ্বাণীটির মধ্যে পার্থক্য সম্পর্কে পড়ার পরামর্শ দিচ্ছি

দীর্ঘ গল্প সংক্ষিপ্ত : "ভবিষ্যদ্বাণী বার্তা বাঁধাই বলা পদ্ধতির ব্যবহার করে - এর অর্থ এই যে পদ্ধতির আচরণ সময়ের সাথে পরিবর্তিত হয় না, বরং অন্য পদ্ধতি দ্বারা পরিবর্তিত হয়।"

কভার রিয়েল ওয়ার্ল্ড সমস্যাযুক্ত কোড

class Processor
{
    /**
     * @var MutatorResolver
     */
    private $mutatorResolver;

    /**
     * @var ChunksStorage
     */
    private $chunksStorage;

    /**
     * @param MutatorResolver $mutatorResolver
     * @param ChunksStorage   $chunksStorage
     */
    public function __construct(MutatorResolver $mutatorResolver, ChunksStorage $chunksStorage)
    {
        $this->mutatorResolver = $mutatorResolver;
        $this->chunksStorage   = $chunksStorage;
    }

    /**
     * @param Chunk $chunk
     *
     * @return bool
     */
    public function process(Chunk $chunk): bool
    {
        $mutator = $this->mutatorResolver->resolve($chunk);

        try {
            $chunk->processingInProgress();
            $this->chunksStorage->updateChunk($chunk);

            $mutator->mutate($chunk);

            $chunk->processingAccepted();
            $this->chunksStorage->updateChunk($chunk);
        }
        catch (UnableToMutateChunkException $exception) {
            $chunk->processingRejected();
            $this->chunksStorage->updateChunk($chunk);

            // Log the exception, maybe together with Chunk insert them into PostProcessing Queue
        }

        return false;
    }
}

পিএইচপিউনিট প্রফেসি সলিউশন

class ProcessorTest extends ChunkTestCase
{
    /**
     * @var Processor
     */
    private $processor;

    /**
     * @var MutatorResolver|ObjectProphecy
     */
    private $mutatorResolverProphecy;

    /**
     * @var ChunksStorage|ObjectProphecy
     */
    private $chunkStorage;

    public function setUp()
    {
        $this->mutatorResolverProphecy = $this->prophesize(MutatorResolver::class);
        $this->chunkStorage            = $this->prophesize(ChunksStorage::class);

        $this->processor = new Processor(
            $this->mutatorResolverProphecy->reveal(),
            $this->chunkStorage->reveal()
        );
    }

    public function testProcessShouldPersistChunkInCorrectStatusBeforeAndAfterTheMutateOperation()
    {
        $self = $this;

        // Chunk is always passed with ACK_BY_QUEUE status to process()
        $chunk = $this->createChunk();
        $chunk->ackByQueue();

        $campaignMutatorMock = $self->prophesize(CampaignMutator::class);
        $campaignMutatorMock
            ->mutate($chunk)
            ->shouldBeCalled();

        $this->mutatorResolverProphecy
            ->resolve($chunk)
            ->shouldBeCalled()
            ->willReturn($campaignMutatorMock->reveal());

        $this->chunkStorage
            ->updateChunk($chunk)
            ->shouldBeCalled()
            ->will(
                function($args) use ($self) {
                    $chunk = $args[0];
                    $self->assertTrue($chunk->status() === Chunk::STATUS_PROCESSING_IN_PROGRESS);

                    $self->chunkStorage
                        ->updateChunk($chunk)
                        ->shouldBeCalled()
                        ->will(
                            function($args) use ($self) {
                                $chunk = $args[0];
                                $self->assertTrue($chunk->status() === Chunk::STATUS_PROCESSING_UPLOAD_ACCEPTED);

                                return true;
                            }
                        );

                    return true;
                }
            );

        $this->processor->process($chunk);
    }
}

সারসংক্ষেপ

আবার, ভবিষ্যদ্বাণী আরও দুর্দান্ত! আমার কৌশলটি হ'ল ভবিষ্যদ্বাণীটির বার্তাবাহক বাঁধার প্রকৃতিটি উত্তোলন করা এবং যদিও এটি দুঃখজনকভাবে একটি সাধারণ, কলব্যাক জাভাস্ক্রিপ্ট নরকের কোড হিসাবে দেখা যাচ্ছে, এটি $ স্ব = $ এর সাথে শুরু হয়েছে ; যেহেতু আপনাকে খুব কমই এরকম ইউনিট পরীক্ষা লিখতে হবে বলে আমি মনে করি এটি একটি দুর্দান্ত সমাধান এবং এটি অনুসরণ করা, ডিবাগ করা অবশ্যই সহজ, কারণ এটি প্রোগ্রামটির বাস্তবায়নটির বর্ণনা দেয়।

বিটিডব্লিউ: দ্বিতীয় বিকল্প রয়েছে তবে কোডটি যা আমরা পরীক্ষা করছি তা পরিবর্তন করা দরকার। আমরা সমস্যা সমাধানকারীদের গুটিয়ে রাখতে এবং তাদের একটি পৃথক শ্রেণিতে স্থানান্তর করতে পারি:

$chunk->processingInProgress();
$this->chunksStorage->updateChunk($chunk);

মোড়ানো হতে পারে:

$processorChunkStorage->persistChunkToInProgress($chunk);

এবং এটি কিন্তু তবে আমি এর জন্য অন্য একটি ক্লাস তৈরি করতে চাইনি, তাই আমি প্রথমটিকে পছন্দ করি।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.