web-dev-qa-db-ja.com

セッターを使用する関数を単体テストするにはどうすればよいですか?

私はリポジトリパターンデザインを使用していて、自分のメソッドの1つに対する単体テストを作成するときに障害にぶつかりました。私は単体テストを書くのがかなり新しいので、どんな助けにも感謝します!

製品を作成し、セッターを使用してデータを設定するメソッドがあるとします。

_public function addProduct(array $data)
{
    $new = $this->repository->make(); // returns new Product object

    $new->setTitle($data['title']);
    $new->setPrice($data['price']);
    $new->setImage($data['image']);
    $new->setStock($data['stock']);

    return $this->repository->save($new); // returns bool
}
_

このメソッドの単体テストを作成しているとき、実際に何をテストする必要がありますか?

  1. 戻り値の型を確認して、そのままにしておくべきですか?
  2. make()の戻りをモックして、すべてのセッターが実行されたことを確認する必要がありますか?
  3. repositoryだけをモックして、make()およびsave()が実行されたことを確認する必要がありますか?

最初は、3つのオプションすべてを使用することにしました。しかし、私の懸念は、オプション2を開始したときからあり、すべてのセッターが実行されたことを確認するテストを作成していました。

単体テストは、すべてのセッターが実行されたかどうかを本当に心配する必要がありますか?さらにフィールドを追加するとどうなりますか?これを行うと、メソッドが実際に実行されたとおりに実行されたときに、最小の変更によって単体テストが失敗する可能性があることを意味するようです。


これまでに単体テストを作成した方法ですが、それがどれほど厳密かは本当にわかりません

_public function testAddProductAddsProductWithCorrectAttributes()
{
    $newMock = Mockery::make(ProductInterface::class)
                    ->shouldReceive('setTitle')
                    ->withArgs(['Test title'])
                    ->shouldReceive('setPrice')
                    ->withArgs([10.99])
                    ->shouldReceive('setImage')
                    ->withArgs(['/foobar.jpg'])
                    ->shouldReceive('setStock')
                    ->withArgs(['In Stock']);

    $repoMock = Mockery::make(RepositoryInterface::class)
                    ->shouldReceive('make')
                    ->andReturn($newMock)
                    ->shouldReceive('save')
                    ->withArgs([$newMock])
                    ->andReturn(true);

    $service = new Service($repoMock);

    $add = $service->addProduct([
        'title' => 'Test title',
        'price' => 10.99,
        'image' => '/foobar.jpg',
        'stock' => 'In Stock'
    ]);

    $this->assertTrue($add);
}
_
2
Dan Johnson

リポジトリをテストする場合、テストする必要があるのは、入力した内容を取得できるかどうかです。

そう...(言い訳疑似コード)

$data = ..//whatever
addProduct(array $data)
$actual = getProduct(id)

Assert $actual == $data

セッターが機能しない場合、これは明らかに失敗します。しかし、すべてのセッターを明示的にテストするわけではありません

7
Ewan

addProduct()の目的は、(a)新しい製品が存在すること、および(b)引数で指定されたフィールド値が製品にあることを確認することです。したがって、はい、ユニットテストでは、すべてのセッターが実行されたかどうか、そしてそれらがallオブジェクトの属性であるかどうかを完全に注意する必要があります。

気にしないと、属性のセットが変更されたときに欠陥が発生する可能性が非常に高くなります。現状のテストスイートでは、新しい属性を導入するとすぐに自動的に警告が表示されます。私を信じて、迷惑な通知は気づかれない欠陥よりwayより良いです。

3
Kilian Foth