Class Based Model Factories With States

Published 1 month ago by xtremer360

I have the following two tests. One tests the length of how long wrestlers won championships and the other tests current champions (not lost) and past (lost) championships. If you wondering about the Fascade Factory I got it from the following link.

https://tighten.co/blog/tidy-up-your-tests-with-class-based-model-factories

I'm trying to figure out what I can do to the ChampionshipFactory class so that it can accept states for the championship. In the link I provided it shows how to add states however I have a use case of having states of current and past where current has a won_on date that would need to be the set based on the title's introduced_at field. Then the lost_on would be a time after the title was won. So I'm trying to figure out how I can get BOTH tests to pass.

The reason why I'm trying to figure out how to do the states the way need is because its more descriptive/readable to me about what the test is above and I don't need to be explicit about the won_on and lost_on dates for the current_titles_held_returns_a_collection_of_active_titles test because its not testing dates of when it was won. I can get the test to pass if I add those values but I figure if I can get it refactored the way I want then I wouldn't need to.

/** @test */
    public function it_can_get_the_champion_with_the_longest_title_reign()
    {
        $wrestlerA = factory(Wrestler::class)->create();
        $wrestlerB = factory(Wrestler::class)->create();
        $wrestlerC = factory(Wrestler::class)->create();
        $title = factory(Title::class)->create();

        ChampionshipFactory::forWrestler($wrestlerA)
                                                  ->forTitle($title)
                                                  ->wonOn(Carbon::parse('2018-01-01'))
                          ->lostOn(Carbon::parse('2018-01-10'))
                          ->create();
        ChampionshipFactory::forWrestler($wrestlerB)
                          ->forTitle($title)
                          ->wonOn(Carbon::parse('2018-01-10'))
                          ->lostOn(Carbon::parse('2018-01-19'))
                          ->create();
        ChampionshipFactory::forWrestler($wrestlerC)
                          ->forTitle($title)
                          ->wonOn(Carbon::parse('2018-01-19'))
                          ->lostOn(Carbon::parse('2018-01-20'))
                          ->create();

        $champions = $this->repository->longestTitleReigns($title);

        $this->assertTrue($champions->contains($wrestlerA));
        $this->assertTrue($champions->contains($wrestlerB));
    }
/** @test */
    public function current_titles_held_returns_a_collection_of_active_titles()
    {
        $wrestler = factory(Wrestler::class)->create();
        $currentChampionshipA = ChampionshipFactory::states('current')
                                                ->forWrestler($wrestler)
                                                ->create();
        $currentChampionshipB = ChampionshipFactory::states('current')
                                                ->forWrestler($wrestler)
                                                ->create();
        $pastChampionship = ChampionshipFactory::states('past')
                                                ->forWrestler($wrestler)
                                                ->create();

        $currentTitlesHeld = $wrestler->currentTitlesHeld;

        $this->assertTrue($currentTitlesHeld->contains('id', $currentChampionshipA->title_id));
        $this->assertTrue($currentTitlesHeld->contains('id', $currentChampionshipB->title_id));
        $this->assertFalse($currentTitlesHeld->contains('id', $pastChampionship->title_id));
    }
<?php

use Carbon\Carbon;
use App\Models\Title;
use App\Models\Wrestler;
use App\Models\Championship;

class ChampionshipFactory
{
    private $wrestler;
    private $title = null;
    private $wonOn = null;
    private $lostOn = null;
    private $titleDefenses = 0;
    private $states = [];

    public function __construct()
    {
        $this->resetProperties();
    }

    public function states($states)
    {
        $this->states = $states;

        return $this;
    }

    public function create()
    {
        if (is_null($this->title)) {
            $this->title = factory(Title::class)->create();
            $this->wonOn = $this->title->introduced_at->copy()->addMonth();
        } elseif (!is_null($this->title) && is_null($this->wonOn)) {
            if ($this->title->champions()->exists()) {
                $dateLastChampionWon = $this->title->fresh()->currentChampion->pivot->won_on;
                $dateOfTitleChange = $dateLastChampionWon->copy()->addMonth();
                $this->title->fresh()->currentChampion->loseTitle($this->title, $dateOfTitleChange);
                $this->wonOn = $dateOfTitleChange;
            } else {
                $this->wonOn = $this->title->introduced_at->copy()->addMonth();
            }
        }

        $champion = factory(Championship::class)->states($this->states)->create([
            'wrestler_id' => $this->wrestler->id ?? factory(Wrestler::class)->create()->id,
            'title_id' => $this->title->id,
            'won_on' => $this->wonOn,
            'lost_on' => $this->lostOn,
            'successful_defenses' => $this->titleDefenses,
        ]);

        $this->resetProperties();

        return $champion;
    }

    public function forWrestler(Wrestler $wrestler)
    {
        $this->wrestler = $wrestler;

        return $this;
    }

    public function forTitle(Title $title)
    {
        $this->title = $title;

        return $this;
    }

    public function wonOn(Carbon $start)
    {
        $this->wonOn = $start;

        return $this;
    }

    public function lostOn(Carbon $end)
    {
        $this->lostOn = $end;

        return $this;
    }

    public function withSuccessfulTitleDefenses($count)
    {
        $this->titleDefenses = $count;

        return $this;
    }

    public function resetProperties()
    {
        if (!is_null($this->wrestler)) {
            $this->wrestler = null;
        }

        if (!is_null($this->title)) {
            $this->title = null;
        }

        if ($this->titleDefenses != 0) {
            $this->titleDefenses = 0;
        }

        if (! is_null($this->wonOn)) {
            $this->wonOn = null;
        }

        if (! is_null($this->lostOn)) {
            $this->lostOn = null;
        }
    }
}

xtremer360

Any ideas to this?

Please sign in or create an account to participate in this conversation.