Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Filtrar los dinos hambrientos

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

En lugar de ver nuestros dinos en el tablero, vemos un TypeError paraGithubService:

El valor devuelto debe ser del tipo HealthStatus, null devuelto

Eso no hace un gran trabajo para decirnos cuál es realmente el problema. Gracias al seguimiento de la pila, parece que está siendo causado por una etiqueta Status: Hungry. ¡Sí! En GitHub, parece que Dennis vuelve a tener hambre después de terminar su rutina diaria de ejercicios.

Nuestro Enum también tiene hambre

Mirando HealthStatus, no tenemos un caso de dinos hambrientos:

... lines 1 - 2
namespace App\Enum;
enum HealthStatus: string
{
case HEALTHY = 'Healthy';
case SICK = 'Sick';
}

Así que añade case HUNGRY que devuelve Hungry... y luego refresca el tablero.

... lines 1 - 2
namespace App\Enum;
enum HealthStatus: string
{
case HEALTHY = 'Healthy';
case SICK = 'Sick';
case HUNGRY = 'Hungry';
}

Y... ¡Ya! No hay más errores...

Pero, espera... Dice que Dennis no acepta visitas. No está enfermo, sólo tiene hambre. GenLab dijo que sólo los dinos enfermos no deberían estar en exposición. Además, ¿quién no quiere ver lo que le pasa a la cabra?

Prueba Los dinos hambrientos pueden tener visitas

En DinosaurTest, tenemos que afirmar que los dinos hambrientos pueden recibir visitas. Hmm... Creo que podríamos utilizar testIsNotAcceptingVisitorsIfSick() para esto. Sí, eso es lo que haremos. A continuación, añade un healthStatusProvider() que devuelva\Generator y para el primer conjunto de datos yield 'Sick dino is not accepting visitors'. En el array di HealthStatus::SICK, y false. A continuación, yield 'Hungry dino is accepting visitors' con [HealthStatus::HUNGRY, true]:

... lines 1 - 8
class DinosaurTest extends TestCase
{
... lines 11 - 58
public function healthStatusProvider(): \Generator
{
yield 'Sick dino is not accepting visitors' => [HealthStatus::SICK, false];
yield 'Hungry dino is accepting visitors' => [HealthStatus::HUNGRY, true];
}
}

Arriba, añade la anotación @dataProvider para que podamos utilizar healthStatusProvider(). Ya que estamos aquí, cambia el nombre del método a testIsAcceptingVisitorsBasedOnHealthStatus y añade los argumentos HealthStatus $healthStatus y bool $expectedVisitorStatus:

... lines 1 - 8
class DinosaurTest extends TestCase
{
... lines 11 - 49
/**
* @dataProvider healthStatusProvider
*/
public function testIsAcceptingVisitorsBasedOnHealthStatus(HealthStatus $healthStatus, bool $expectedVisitorStatus): void
{
... lines 55 - 59
}
public function healthStatusProvider(): \Generator
{
yield 'Sick dino is not accepting visitors' => [HealthStatus::SICK, false];
yield 'Hungry dino is accepting visitors' => [HealthStatus::HUNGRY, true];
}
}

Dentro pon la salud con $healthStatus y luego sustituye assertFalse() porassertSame($expectedStatus) es idéntico a $dino->isAcceptingVisitors():

... lines 1 - 8
class DinosaurTest extends TestCase
{
... lines 11 - 49
/**
* @dataProvider healthStatusProvider
*/
public function testIsAcceptingVisitorsBasedOnHealthStatus(HealthStatus $healthStatus, bool $expectedVisitorStatus): void
{
... lines 55 - 56
$dino->setHealth($healthStatus);
self::assertSame($expectedVisitorStatus, $dino->isAcceptingVisitors());
}
public function healthStatusProvider(): \Generator
{
yield 'Sick dino is not accepting visitors' => [HealthStatus::SICK, false];
yield 'Hungry dino is accepting visitors' => [HealthStatus::HUNGRY, true];
}
}

¡Uf, eso ha sido mucho trabajo!

Pruebas de filtrado

Veamos si ha funcionado.. Ejecuta:

./vendor/bin/phpunit --filter testIsAcceptingVisitorsBasedOnHealthStatus

¿Ves lo que he hecho? Para centrarnos sólo en esta prueba, podemos añadir el conjunto --filter al nombre completo o parcial de una clase de prueba, de un método o de cualquier otra cosa. Esto resulta muy útil cuando tienes un conjunto de pruebas grande y sólo quieres ejecutar una o unas pocas pruebas.

En cualquier caso, el dino hambriento no acepta a los visitantes y falla:

Fallo al afirmar que falso es verdadero.

Mirando Dinosaur::isAcceptingVisitors(), para tener en cuenta a los dinos hambrientos, tenemos que devolver $this->health no es igual a HealthStatus::SICK:

... lines 1 - 6
class Dinosaur
{
... lines 9 - 55
public function isAcceptingVisitors(): bool
{
return $this->health !== HealthStatus::SICK;
}
... lines 60 - 64
}

Veamos qué ocurre cuando lo ejecutamos:

./vendor/bin/phpunit --filter "Hungry dino is accepting visitors"

Y... ¡boom! Nuestra prueba del dino hambriento pasa ahora, ¡ja! Sí, también podemos utilizar claves de proveedores de datos con la bandera filter. Pero para asegurarnos de que no impedimos que los dinos sanos tengan visitas, ejecuta

./vendor/bin/phpunit

Um... ¡Sí! Todos los puntos y ningún error. ¡Genial! No hemos destrozado el parque. Echa un vistazo al tablero de control, actualízalo y ¡ya! Dennis puede volver a comer con los clientes del parque. Aunque creo que deberíamos ser proactivos y lanzar una excepción más clara por si alguna vez vemos alguna etiqueta de estado futura que no conozcamos. Hagamos eso a continuación.

Leave a comment!

2
Login or Register to join the conversation
Jesus Avatar
Jesus Avatar Jesus | posted hace 4 meses | edited

Hi, one question.

When we rename de method to testIsAcceptingVisitorsBasedOnHealthStatus() I think the data provider must add

 yield 'Healthy dino is accepting visitors' => [HealthStatus::Healthy,true];

¿Why? Because with this state is accepting visitors (as says de method)

Reply

Hey Jesus,

Actually, probably the reverse :) We do want to test cases with HealthStatus::SICK and HealthStatus::HUNGRY here, so probably the better test name would be to testIsNotAcceptingVisitorsBasedOnHealthStatus()... but it's minor and the current name technically also good because we made this test name kind of generic, i.e. saying in general here. The actual "value" of the expected visitor status should is passed as the 2nd argument and either true or false base on the given status.

I hope this clarify things for you :)

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "symfony/asset": "6.1.*", // v6.1.0
        "symfony/console": "6.1.*", // v6.1.4
        "symfony/dotenv": "6.1.*", // v6.1.0
        "symfony/flex": "^2", // v2.2.3
        "symfony/framework-bundle": "6.1.*", // v6.1.4
        "symfony/http-client": "6.1.*", // v6.1.4
        "symfony/runtime": "6.1.*", // v6.1.3
        "symfony/twig-bundle": "6.1.*", // v6.1.1
        "symfony/yaml": "6.1.*" // v6.1.4
    },
    "require-dev": {
        "phpunit/phpunit": "^9.5", // 9.5.23
        "symfony/browser-kit": "6.1.*", // v6.1.3
        "symfony/css-selector": "6.1.*", // v6.1.3
        "symfony/phpunit-bridge": "^6.1" // v6.1.3
    }
}
userVoice