2

私はテストが初めてで、NewsCreator create メソッドの最初の if ステートメントをカバーする単体テストを作成しようとしています。

この質問には 2 つの部分があります。

最初: モックされたバリデータとリポジトリを処理するには、NewsCreator をどのようにインスタンス化する必要がありますか?

2 番目: このパスをテストする正しい方法は何でしょうか?

テストが必要なクラスを呼び出すコントローラー メソッドは次のとおりです。

public function store()
{
    $creator = new NewsCreator($this);
    return $creator->create(Input::all());
}

テストしたいクラス、NewsCreator は次のとおりです。

<?php namespace WHS\Portal\News;

class NewsCreator {

    protected $listener;
    protected $repository;
    protected $validator;
    protected $errors;

    public function __construct($listener, NewsRepositoryInterface $repository, NewsValidator $validator)
    {
        $this->listener = $listener;
        $this->repository = $repository;
        $this->validator = $validator;
        $this->errors = [];
    }
    public function create($data)
    {
        if($this->validator->fails($data))
        {
            return $this->listener->newsCreationFails($this->validator->messages());
        }
        if($this->repository->create($data))
        {
            return $this->listener->newsCreationSucceeds();
        }
        return $this->listener->newsCreationFails($this->errors);
    }
}

これは私が書こうとしたテストですが、例外で失敗します:

2) WHS\Portal\Tests\News\NewsCreatorTest::test_failed_validation Mockery\Exception\InvalidCountException: Method fails("foo") from Mockery_1_WHS_Portal_News_NewsValidator should be called exactly 1 times but called 0 times.

<?php namespace WHS\Portal\Tests\News;

    use TestCase;
    use Mockery as m;

    class NewsCreatorTest extends TestCase {

        public function tearDown()
        {
            m::close();
        }

        public function test_failed_validation()
        {
            $newsRepo = m::mock('\WHS\Portal\News\DbNewsRepository["create"]');
            $newsValidator = m::mock('\WHS\Portal\News\NewsValidator["fails"]');

            $listener = new NewsListenerStub();
            $listener = m::mock($listener)->makePartial();

            $newsValidator->shouldReceive('fails')->with('foo')->once()->andReturn(true);
            $listener->shouldReceive('newsCreationFails')->once()->with('foo')->andReturn();

            $newsCreator = new \WHS\Portal\News\NewsCreator($listener,$newsRepo,$newsValidator);
            $newsCreator->create([]);
        }
    }

更新されたテスト:

use TestCase;
use Mockery as m;

class NewsCreatorTest extends TestCase {

    public function tearDown()
    {
        m::close();
    }

    public function test_failed_validation()
    {
        $newsRepo = m::mock('\WHS\Portal\News\DbNewsRepository["create"]');
        $newsValidator = m::mock('\WHS\Portal\News\NewsValidator["fails"]');

        $listener = m::mock('\WHS\Portal\Tests\News\NewsListenerStub["newsCreationFails"]');

        $newsValidator->shouldReceive('fails')->with([])->once()->andReturn(true);
        $newsValidator->shouldReceive('messages')->once();
        $listener->shouldReceive('newsCreationFails')->once()->with('foo')->andReturn('foo-bar');

        $newsCreator = new \WHS\Portal\News\NewsCreator($listener,$newsRepo,$newsValidator);

        $result = $newsCreator->create([]);
        $this->assertEquals('foo-bar', $result);
    }
}

スタブ クラス:

class NewsListenerStub
{
    public function newsCreationFails($data)
    {
        return $data;
    }
}

助けてください。

ありがとう。

4

1 に答える 1

1

メソッドは、クラスの引数でfails()呼び出されます。$data単体テストでは、空の配列を data として渡していますcreate([])。validatorMock での引数の期待はfails()、パラメーターで呼び出されることを期待していますfoo。空の配列と一致するように変更する必要があります。

$newsValidator->shouldReceive('fails')->with([])->once()->andReturn(true);

validator->messages()また、クラスでも呼び出されているため、validatorMock でメソッドを指定する必要があります。

$newsValidator->shouldReceive('messages')->once();

NewsCreationFailsこのテストが本当に意味を成すためには、 の結果がの戻り値と一致することをアサートする必要がありcreate()ます。

$listener->shouldReceive('newsCreationFails')->once()->with('foo')->andReturn('foo-bar');
...
$result = $newsCreator->create([]);

$this->assertEquals('foo-bar', $result);
于 2014-02-16T09:37:54.983 に答える