Learning Testing and mocking classes & Private Methods

Posted 1 year ago by longestdrive

I'm starting to learn testing - my laravel 5.5 app and gradually overcoming obstacles.

This is day 4 so a new challenge for me.

I'm trying to test a database record is created - I can do this and the tests work.

However the class that creates the record interacts with another class (a Cart class)- sends it some parameters and gets back a value.

I'm trying to isolate the test to this class so have tried to mock the class but I'm fairly sure I don't know what I'm doing here,

This is my test class:

class CreateBookingTest extends TestCase
{
    private $booking;

    public function setUp()
    {
        parent::setUp();
        $this->booking = \App::make(\App\Golfmanager\Booking\CreateBooking::class);

    }

    public function test_booking_created()
    {
        $attributes = $this->createAttributes();
        $user = \App\Models\User::find(1);
        $mock = \Mockery::mock(Cart::class);
          $mock->shouldReceive(['getCartGroupSize', 'instance'])
              ->with('greenfee')
              ->andReturn(1);

        $booking = $this->booking->handle($attributes, $user, 'greenfee');

        $this->assertEquals(1532, $booking->customer_id);
        $this->assertEquals(1, $booking->user_id);
        $this->assertEquals(1, $booking->group_size);

    }

    private function createAttributes()
    {
        $attributes = [
            'customer_id'=>1532,
            'play_date'=>'01/02/2018',
            'am_tee'=>'10:00 AM',
            'howBooked'=>'Drop In',
            'cartCount'=>1
        ];

        return $attributes;
    }
}

Here's the class I'm testing:

class CreateBooking
{
    /**
     * @var ReservationRepository
     */
    private $reservationRepository;
    /**
     * @var CustomerRepository
     */
    private $customerRepository;
    private $customer;
    private $groupSize = 0;
    private $costs = 0;
    private $saleTotal;
    private $booking;
    /**
     * @var Cart
     */
    private $cart;

    /**
     * CreateBooking constructor.
     * @param ReservationRepository $reservationRepository
     * @param CustomerRepository $customerRepository
     * @param Cart $cart
     */
    public function __construct(
        ReservationRepository $reservationRepository,
        CustomerRepository $customerRepository,
        Cart $cart
    )
    {
        $this->reservationRepository = $reservationRepository;
        $this->customerRepository = $customerRepository;
        $this->cart = $cart;
    }

    public function handle(Array $attributes, $user, $type = 'greefee')
    {

        $this->setUpBooking($attributes)
            ->createBooking($attributes)
            ->attachUser($user)
            ->attachCustomer();

        return $this->booking;
    }

    private function setUpBooking($attributes)
    {
        $this->setCustomer($attributes['customer_id']);
        $this->setGroupSize();
        $this->setCosts();
        $this->setSaleTotal();

        return $this;
    }

    private function setCustomer($customer_id)
    {
        $this->customer = $this->customerRepository->findById($customer_id);
    }

    private function setGroupSize()
    {
        $this->groupSize = $this->cart->getCartGroupSize('greenfee');
    }

//    Review: should this be here?
    private function setCosts()
    {
        $this->costs = $this->cart->getCartCostsTotal('greenfee');
    }

//    review: Should this be here?
    private function setSaleTotal()
    {
        $this->saleTotal = $this->cart->instance('greenfee')->total();
    }

    private function bookingAttributes($attributes)
    {
        $baseAttributes = array_only($attributes, ['play_date', 'am_tee', 'howBooked']);

        return array_merge($baseAttributes, $this->createTypeSpecificAttributes($attributes));
    }

    private function createTypeSpecificAttributes($attributes)
    {
        $typeSpecificAttributes = [
            'booked_date' => $attributes['play_date'],
            'group_size' => $this->groupSize,
            'sale_total' => $this->saleTotal,
            'costs_total' => $this->costs,
            'notes' => "Direct sale from `green fee\n",
            'status' => 'invoiced',
            'directSale' => 1,
            'event_type' => 'Golf',

        ];

        return $typeSpecificAttributes;
    }

    private function createBooking($attributes)
    {
        $this->booking = $this->reservationRepository->create($this->bookingAttributes($attributes));

        return $this;
    }

    private function attachCustomer()
    {
        $this->customer->reservation()->save($this->booking);

        return $this;

    }

    private function attachUser($user)
    {
        $user->reservation()->save($this->booking);

        return $this;
    }


}

I wanted to assert that first the class is called within the class I'm testing - makes use of the instance method and the getCartGroupSize method and returns a value

When running the test I can see 5 assertions but get one failure - because the value being returned by the mocked class doesn't appear to be used in the class I'm testing

Very confused how to correctly implement

I've tried moving the initiation of the class I'm testing after I've created the Mock but no change

ANy help appreciated

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

Reply to

Use Markdown with GitHub-flavored code blocks.