我尝试创建一个团队,然后将该团队添加到游戏中,然后将该游戏添加到该事件中,但是,当创建游戏时,它会自动生成附加到该事件的事件。在正常情况下,这很好但是因为我测试了团队加入时与他们的第一个游戏所在的事件相比,那么我需要创建一个具有特定日期的事件。我无法先创建活动,因为必须首先创建游戏才能将其添加到游戏中。
有没有人建议纠正我的逻辑,以便我可以正确创建游戏和事件?
我不知道我应该为这个边缘案件做些什么。
/** @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'),
];
});
答案 0 :(得分:2)
您应该使用与在应用程序中执行此操作时相同的逻辑:
•创建活动
•为比赛添加游戏
•在游戏中添加团队
如果您需要测试日期,请在以下后编辑它们:)
答案 1 :(得分:2)
注意:下面显示的源代码基于一些假设,因为在原始问题中未给出例如
Event
,Game
和Team
等模型的特定实现。考虑添加一个包含问题来源的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
验证的测试用例可能看起来像下面那样,使用预言 - 要测试的实例被命名为$subject
以使其清楚,要测试的主题是什么(作为编写测试的常见最佳实践):
/**
* @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')
);
}
这样,您的Event
,Game
和Team
模型不再依赖任何工厂实现,而是使用预言模拟属性和行为。因此,如果工厂被更改或重构,您只需要调整那些断言对象重构的测试 - 可以跳过提到的beforeFirstGameDateValidatorRejectsLateApplications
,因为它没有对这些工厂的硬依赖性。
正如开头所提到的,Event
,Game
和Team
的方法和属性只是假设,因为在撰写此答案时真正的实现是未知的。
参考文献: