Unit testing advice

Published 2 weeks ago by RossUK

Hi, I am trying to do some unit/feature testing and take a TDD approach to a new Laravel project. I am trying to get my head around which tests I should be writing and also which tests are a feature or a unit. As an example to start off with I have a Customer model and a Contact model. When the app is finished an authenticated end user will be able to create edit and delete customers and contacts and also add contacts to a customer. Before any webforms exists what tests should/would be good to write for this.

here what I have so far but want to check I am not going completely in the wrong direction :)

<?php

namespace Tests\Unit;

use App\Customer;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;


class CustomerTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */

    use RefreshDatabase;
    use WithFaker;

    protected $customer;

    public function setUp()
    {
        parent::setUp();
        $this->customer = factory('App\Customer')->create();
    }

    /** @test */
     public function testCustomerCanBeCreated() 
     {
         $this->assertEquals(1, Customer::count());
     }

     /** @test */
    public function canEditCustomer() 
    {
        //set test data
        $data = [
            'company_name' => "New Company Inc",
        ];

        //make post request with test data to named route
        $this->post(route('customers.store'), $data)->assertStatus(201);
        $this->call('POST', '[email protected]', $data);

        //get first record
        $customer = Customer::first();

        //check database values exist
        $this->assertEquals($data['company_name'], $customer->company_name);

    }


    public function canUpdateCustomer() {}
    public function canDeleteCustomer() {}
    public function canAddContactToCustomer() {}
    public function canGetCustomerContacts() {}



}

Many Thanks

Best Answer (As Selected By RossUK)
manogi

At browser level (you probably mean Dusk) ist different. You will run into problems using RefreshDatabase, for example.

But Dusk is a great tool! I use it to make sure clicking buttons and filling forms etc. works the way it is supposed to. Also it is great to test stuff that has been added to your site by JavaScript.

But will have to rely on certain DOM elements to exist and having specific classes, IDs or attributes - that is a specificity which should not matter in feature tests.

For testing routes I would stick to Feature Test (HTTP Tests) - it is much simpler, and in tests one should stick to the simplest possible way, I think.

The feature test should be

"An authenticated User can call route('make-some-noise') and some noise should be made",

That test should keep working, no matter how you structure your frontend code.

You can of course write a Browser test:

"Someone visits the login page, fills in the login form (targeted by ìnput[name=username]` etc), clicks the Submit button, lands on another page, clicks the Button "Make some noise"....

And so on, but that probably should be broken up into multiple smaller test methods. And in my opinion this should not replace the Feature test.

manogi
manogi
2 weeks ago (35,075 XP)

Instead of writing in detail how I would go about this I recommend watching the Unlocking Badges Workshop or Let's build a forum with TDD.

Jeffrey jumps between Feature and Unit tests. But when you start from zero, it makes sense to start with a feature of your app and write some feature tests. In the middle of those tests you might find the need to write a unit test and then go back to the feature test...

As for what is a Feature test and what is a Unit test: Watching those videos will explain it much better than I can... a feature test tests features (duh!) of your app, for example "An Authenticated User Can Delete Customers". That would probably test a http endpoint used to delete Customers.

While writing said test ("An Authenticated User Can Delete Customers") you might find you want to write a test to make sure that deleting a Customer with the Eloquent method delete will not (or WILL, whatever is correct in your case) delete the Contacts which "belonged" to the deleted Customer. That would belong to the unit tests, in my book.

But Jeffrey explains it much better ;-)

manogi
manogi
2 weeks ago (35,075 XP)

Your example falls more under Feature Tests - it tests routes or http endpoints of your application. A Feature is (in my opinion) something your App DOES.

A Unit is a small (the "smallest"?) part of your app, which can be tested in "isolation". For example, if you have methods on your model Customer, you might (it is totally up to you) want to test each method separately in Tests\Unit\CustomerTest.

RossUK

Hi,

Thanks. I have been going through the forum tutorial and trying to apply the testing logic to my own example. Thanks for helping me clear up the differences between a feature and a unit.

Is testing at route level a typical work flow or would it be better to test at browser level therefore testing the routing at the same time? I suppose that's what Jeffery does in the forum tutorial :)

manogi
manogi
2 weeks ago (35,075 XP)

At browser level (you probably mean Dusk) ist different. You will run into problems using RefreshDatabase, for example.

But Dusk is a great tool! I use it to make sure clicking buttons and filling forms etc. works the way it is supposed to. Also it is great to test stuff that has been added to your site by JavaScript.

But will have to rely on certain DOM elements to exist and having specific classes, IDs or attributes - that is a specificity which should not matter in feature tests.

For testing routes I would stick to Feature Test (HTTP Tests) - it is much simpler, and in tests one should stick to the simplest possible way, I think.

The feature test should be

"An authenticated User can call route('make-some-noise') and some noise should be made",

That test should keep working, no matter how you structure your frontend code.

You can of course write a Browser test:

"Someone visits the login page, fills in the login form (targeted by ìnput[name=username]` etc), clicks the Submit button, lands on another page, clicks the Button "Make some noise"....

And so on, but that probably should be broken up into multiple smaller test methods. And in my opinion this should not replace the Feature test.

RossUK

Really great info thanks very much :)

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