deshiloh's avatar

Test custom service

Hi,

I would like to test my custom service :

<?php

namespace App\Services;

use App\Models\Reservation;
use Illuminate\Support\Carbon;
use Spatie\GoogleCalendar\Event;

class GoogleCalendarService
{
    /**
     * Create a Google Event and return the event ID
     * @param Reservation $reservation
     * @return string
     */
    public function createEvent(Reservation $reservation): string
    {
        $event = new Event;

        $piloteLabel = ($reservation->pilote_id === null) ? 'En attente' : $reservation->piltoe->full_name;

        $event->name = sprintf(
            'Course n°%s - %s / %s / %s',
            $reservation->reference,
            ucfirst($reservation->user->entreprise->nom),
            $reservation->passager->nom,
            'plt: '. $piloteLabel
        );


        $description = "Société: %s\n";
        $description .= "Passager: %s\n";
        $description .= "Tel passager: %s\n";
        $description .= "Email: %s\n\n";
        $description .= "Assistante: %s\n";
        $description .= "Tel assistante: %s\n";
        $description .= "Email assistante: %s\n\n";
        $description .= "Pilote: %s\n";
        $description .= "Date de la course: %s\n";
        $description .= "Adresse de départ: %s\n";
        $description .= "Provenance / N°: %s\n\n";
        $description .= "Adresse de destination: %s\n";
        $description .= "Destination / N°: %s\n\n";
        $description .= "Commentaires: %s\n\n";
        $description .= "Tarif : \n\n";
        $description .= "\nLien: %s\n";
        $description .= "\n\nMotobleu\n26-28 rue Marius Aufan\n92300 Levallois Perret\nTél: +33647938617\[email protected]\nRCS 824 721 955 NANTERRE"; //company_details

        $phones = implode(' - ', [$reservation->passager->telephone, $reservation->passager->portable]);

        $description = sprintf(
            $description,
            $reservation->user->entreprise->nom,
            $reservation->passager->nom,
            $phones,
            $reservation->passager->email,
            $reservation->user->full_name,
            $reservation->user->telephone,
            $reservation->user->email,
            $piloteLabel,
            $reservation->pickup_date->format('d/m/Y à H\hi'),
            $reservation->display_from,
            $reservation->pickup_origin,
            $reservation->display_to,
            $reservation->drop_off_origin,
            $reservation->comment,
            route('admin.reservations.show', ['reservation' => $reservation->id])
        );

        $event->description = $description;
        $event->startDateTime = Carbon::now();
        $event->endDateTime = Carbon::now()->addHour();
        //$event->addAttendee(['email' => '[email protected]']);

        $savedEvent = $event->save();

        return $savedEvent->id;
    }
}

I would like to test that the save method is called to test that everything is ok. I started like so but I don't know what to do next :

<?php

namespace Tests\Feature;


use App\Services\GoogleCalendarService;
use Mockery\MockInterface;
use Tests\TestCase;

class GoogleCalendarServiceTest extends TestCase
{
    public function testCreateEvent()
    {
        $this->instance(
            GoogleCalendarService::class,
            \Mockery::mock(GoogleCalendarService::class, function (MockInterface $mock) {

                $mock->shouldReceive('save')->once();
            })
        );
    }
}

I'm beginner in testing with laravel.

0 likes
4 replies
Niush's avatar

Shouldn't you be mocking Spatie\GoogleCalendar\Event instead? To check if save is called.

Then mock your service to check createEvent is called?

<?php

namespace Tests\Feature;

use App\Models\Reservation;
use Spatie\GoogleCalendar\Event;
use App\Services\GoogleCalendarService;
use Mockery\MockInterface;
use Tests\TestCase;

class GoogleCalendarServiceTest extends TestCase
{
    public function testGoogleCalenderServiceCanCallCreateEvent()
    {
        $this->mock(GoogleCalendarService::class, function (MockInterface $mock) {
            $mock
                ->shouldReceive('createEvent')
                ->once();
        });

		$reservation = Reservation::factory()->create();
		app(GoogleCalendarService::class)->createEvent($reservation);
    }

    public function testGoogleCalenderServiceCanCreateSpatieEvent()
    {
        $this->mock(Event::class, function (MockInterface $mock) {
            $mock
                ->shouldReceive('save')
                ->once();
        });

		$reservation = Reservation::factory()->create();
		app(GoogleCalendarService::class)->createEvent($reservation);
    }
}

Something like above. Mock your GoogleCalendarService, and test if createEvent is called. Then Mock Spatie Event, and test if save is called.

Probably you will need to do $event = app(Event::class); in your service.

deshiloh's avatar

@Niush Thank you for this, and question, by doing this, it will make all the Event creation happen, how can i just test that the save method is called without trigger all the process ? Should I not mock return values ?

Niush's avatar

@deshiloh

This testGoogleCalenderServiceCanCallCreateEvent test will mock your service. So, your code (service) won't run and Event will not be created.

This testGoogleCalenderServiceCanCreateSpatieEvent test will mock Event class only. So that, the Event, will not be saved. Mockery will handle it. But, all the other code inside your service will still run. You need to trigger the Service createEvent to reach the $event->save() in your code.

If you require (or other dependencies in controllers for example require), then you can add return as well.

deshiloh's avatar

@Niush Sorry I'm just trying your code right now, and I'm having this error : TypeError : Spatie\GoogleCalendar\GoogleCalendarFactory::createForCalendarId(): Argument #1 ($calendarId) must be of type string, null given

Please or to participate in this conversation.