susanBuck / e2-fall22

0 stars 0 forks source link

Issue with asserting game outcomes test #59

Closed berhanwa closed 1 year ago

berhanwa commented 1 year ago

Regarding p3 testing, I hit a snag with the assertion to see when the user has won, lost or tied. In video 6, around the 15 minute mark, 'won' and 'lost' classes were assigned in the index view. Since my rock paper scissors game logic wasn't as pithy, and I had also defined it in the controller, I just printed the results out in my view with {{ }}.

I wasn't sure how to assert the won/lost/tied testing since I didn't define those outcomes in the view file.

I've attached my view and controller code below.

INDEX view:

@if ($choice)
    <div test='results-div' class='results'>
        You chose {{ $choice }}, and the computer chose <span test='computer-outcome'> {{ $computerDraw }}.
        </span>
        In this round, {{ $won }}
    </div>
@endif

CONTROLLER:

    $choice = $this->app->input('choice');

    function drawMove() {
        $moves = ['rock', 'paper', 'scissor'];
        return $moves[rand(0,2)];
}

    function decideWinner($userDraw, $computerDraw) {
        if ($userDraw == $computerDraw) {
            return 'it was a tie. Please try again!';
        } elseif ($userDraw == 'rock') {
            return $computerDraw == 'paper' ? 'the computer won. Please try again!' : 'you won!';
        } elseif ($userDraw == 'paper') {
            return $computerDraw == 'scissor' ? 'the computer won. Please try again!' : 'you won!';
        } elseif ($userDraw == 'scissor') {
            return $computerDraw == 'rock' ? 'the computer won. Please try again!' : 'you won!';
        }
    }

    $userDraw = $_POST['choice'];
    $computerDraw = drawMove();
    $won = decideWinner($userDraw, $computerDraw);
susanBuck commented 1 year ago

I would refactor this to shift the output responsibility away from the controller and more to the view. It'll make testing easier, and is better separation of concerns.

To accommodate this, have decideWinner return a simple value of "tie", "user", or "computer" which you'll use in the view to determine the output.

While rewriting decideWinner we can simplify things by rewriting the logic using this neat math formula.

function decideWinner($userDraw, $computerDraw)
{
    # Convert the move to a numerical value where 0 = rock, 1 = paper, 2 = scissors
    $moves = ['rock', 'paper', 'scissors'];
    $userDraw = array_search($userDraw, $moves);
    $computerDraw = array_search($computerDraw, $moves);

    if ($userDraw == $computerDraw) {
        return 'tie';
    } elseif (($userDraw + 1) % 3 == $computerDraw) {
        return 'computer';
    } else {
        return 'user';
    }
}

Then, in the view, use whatever value decideWinner returned to determine the output:

@if($won == 'tie')
    <div test='winner-tie'>It was a tie. Please try again!</div>
@elseif($won == 'user')
    <div test='winner-user'>You won!</div>
@else 
    <div test='winner-computer'>The computer won. Please try again!</div>
@endif

Note how I added the test attribute to the above divs so you can test for their presence.

Let me know if you have any questions about this.