2017-12-29 16 views
4

チームを作成してゲームに追加し、そのゲームをイベントに追加しようとしていますが、ゲームが作成されると自動的にイベントに添付するイベントが生成されます。通常の状況ではこれは問題ありませんが、最初の試合が行われているイベントと比べてチームの参加がテストされているため、特定の日付のイベントを作成する必要があります。最初にイベントを作成することはできません。なぜなら、ゲームを追加するためにはまずゲームを作成しなければならないからです。テストのあるLaravel Modalファクトリ

ゲームやイベントを正しく作成できるように、私のロジックを修正する提案がありますか?

私はこのエッジケースのために何をする必要があるのか​​わかりません。

/** @test */ 
public function a_team_with_a_game_after_they_started_the_season_cannot_have_their_joined_at_date_after_their_first_match() 
{ 
    $team = factory(Team::class)->create(['joined_at' => '2017-10-08']); 

    $game = GameFactory::create([], [$team]); 
    $event = EventFactory::create(['date' => '2017-10-09'], null, $game); 

    $validator = new BeforeFirstGameDate($team); 

    $this->assertFalse($validator->passes('joined_at', '2017-10-10')); 
    $this->assertEquals('The joined at date cannot be AFTER the team\'s first game.', $validator->message()); 
} 

Factories 

<?php 

use App\Models\Game; 
use App\Models\Team; 

class GameFactory 
{ 
    public static function create($overrides = [], $teams = []) 
    { 
     $match = factory(Game::class)->create($overrides); 

     self::addTeamsForGame($teams, $game); 

     return $game; 
    } 

    /** 
    * @param $teams 
    * @param $game 
    */ 
    public static function addTeamsForGame($teams, $game) 
    { 
     $teamsForGame = []; 

     $numberOfTeamsToAdd = $numberOfTeams - count($teams); 

     if ($numberOfTeamsToAdd) { 
      $teamsForMatch = factory(Team::class, $numberOfTeamsToAdd)->create(); 
      array_push($teams, $teamsForGame); 
     } else { 
      array_push($teams, $teamsForGame); 
     } 

     $match->addTeams($teamsForGame); 
    } 
} 


<?php 

use App\Models\Event; 

class EventFactory 
{ 
    public static function create($overrides = [], $totalNumberOfGames = 8, $games = []) 
    { 
     $event = factory(Event::class)->create($overrides); 

     $numberOfGamesToAdd = $totalNumberOfGames - count($games); 
     $gameToStartAt = count($games) + 1; 

     foreach (array_wrap($games) as $game) { 
      $game->addToEvent($event); 
     } 

     for ($gameNumber = $gameToStartAt; $gameNumber <= $numberOfGamesToAdd; $gameNumber++) { 
      GameFactory::create(['event_id' => $event->id, 'game_number' => $gameNumber]); 
     } 

     return $event; 
    } 
} 


$factory->define(App\Models\Game::class, function (Faker\Generator $faker) { 
    static $order = 1; 
    return [ 
     'event_id' => function() { 
      return factory(App\Models\Event::class)->create()->id; 
     }, 
     'game_number' => $order++, 

    ]; 
}); 

$factory->define(App\Models\Event::class, function (Faker\Generator $faker) { 
    $name = $faker->sentence; 
    return [ 
     'name' => $name, 
     'slug' => str_slug($name), 
     'date' => $faker->dateTimeBetween('-10 years'), 
    ]; 
}); 

答えて

2

注:元の質問では、EventGameTeamなどのモデルの具体的な実装は行われていないため、以下のソースコードはいくつかの前提に基づいています。あなたの実装をより詳細に反映したより具体的な回答を得るために、ソースを含むGitリポジトリを質問に追加することを検討してください。

まず、試験にはいくつかの一般的な備考:(ケースのコード表示は、上記ユニットを中心とし、一つである)

  • 単体テストべきドメイン層のみ試験特定の一態様 - したがって、BeforeFirstGameDateが正常に動作しているが、関連する可能性のあるサービス(データベース)またはオブジェクト再構成のためのファクトリの組み合わせをテストしないようにするために使用される技法は「モック」または「予言」
  • 上のようなコード)は、他の漢実際の実装でテストすることができます(可能であれば "モック"も "予言"もありません)。しかし、偽装されたシナリオでは、工場、モデル、バリデーターのアプリケーション全体をテストしたい場合は、インスタンスのデータベースと言われていることこれら

に基づいてテストを実行し、よりユニット部分に焦点を置く「ユニットテスト」は、あなたのテストは次のようになりますで - テスト単一、分離した単位に焦点を当てこれらの組み合わせではありません。

/** @test */ 
public function eventIsCreated() 
{ 
    ... 
    static::assertSame($expectedEvent, EventFactory::create(...)); 
} 
/** @test */ 
public function teamIsCreated() 
{ 
    ... 
    static::assertSame($expectedTeam, TeamFactory::create(...)); 
} 
/** @test */ 
public function gameIsCreated() 
{ 
    ... 
    static::assertSame($expectedGame, GameFactory::create(...)); 
} 
/** @test */ 
public function beforeFirstGameDateValidatorRejectsLateApplications() 
{ 
    ... 
} 

有効なBeforeFirstGameDateのテストケース

/** 
* @test 
*/ 
public function beforeFirstGameDateValidatorRejectsLateApplications() 
{ 
    $event = $this->prophesize(Event::class); 
    $game = $this->prophesize(Game::class); 
    $team = $this->prophesize(Team::class); 

    $event->getGames()->willReturn([$game->reveal()]); 
    $game->getTeams()->willReturn([$team->reveal()]); 
    $team->get('joined_at')->willReturn('2017-10-08'); 

    $subject = new BeforeFirstGameDate($team->reveal()); 

    static::assertFalse(
     $subject->passes('joined_at', '2017-10-10') 
    ); 
} 

これを:(筆記試験において、一般的なベストプラクティスとして)テストされるべき対象何、$subjectと命名されたテスト対象のインスタンスをそれを明確にするために - ationがちょうど預言を使用して、次のようになります。 EventGameTeamモデルは、工場の実装にはもう依存しませんが、預言を使用してプロパティと動作をシミュレートします。したがって、工場が変更またはリファクタリングされる場合は、オブジェクトの再委託を主張するテストを調整するだけで済みます。たとえば、beforeFirstGameDateValidatorRejectsLateApplicationsは、これらの工場に強く依存しないためスキップできます。冒頭で述べたように

EventGameTeamためのメソッドとプロパティは、実際の実装は、この答えを書いている時点では不明だったのでちょうど仮定しています。

参考文献:

2

あなたは、あなたのアプリケーションでこれをやっているときと同じロジックを使用する必要があります。

•イベント

•チームを追加•イベント

にゲームを追加を作成します。ゲームに

あなたの日付をテストする必要がある場合は、その後にそれらを編集してください:)

+0

私は最初のイベントを作成した場合、私はゲームがそのイベントに追加し、それを渡すために作成されていません。 – user3732216

+0

アプリのワークフローとは何ですか? –

+0

イベントが作成されると、チームはゲームに割り当てられ、イベントに割り当てられます。 – user3732216

関連する問題