testing with laravel

Post on 16-Apr-2017

511 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Designing for Testability with Laravel

Derek Binkley@DerekB_WI

About Me★Lead Developer at National Conference of

Bar Examiners★PHP and Java Developer★MySQL DBA★Father of Three★Second ever talk

About NCBEExamining Bars?

About NCBENo, developing the bar exam for future lawyers.

Plus, supporting state admission authorities.

What will we cover?

What is built in to Laravel for Unit TestingStrategies that make testing easier

Detailed examples

Unit Tests• Lowest level of testing• Typically done by developer• Crucial to Test Driven Design• Tests a Single Unit of Code and Verifies the

Results.

Why don’t developers test?• Think code will get replaced soon.• Think code is straightforward and won’t break.• Tests are hard to write.• Low perceived benefit.• Don’t understand how to design code for

testability.

Laravel and PHPUnit• PHPUnit Available by default

• Tests saved in Tests directory• Tests should extend TestCase class• Tests should be saved in file named *Test.php• Tests method names should begin with test.

What Does Laravel Provide?• Crawler – Gives us a mock browser/client to

run our controllers.

What Does Laravel Provide?• Additional assertions• ->assertResponseOk();• ->assertResponseStatus($code);• ->assertViewHas($key, $value = null);• ->assertViewHasAll(array $bindings);• ->assertViewMissing($key);• ->assertRedirectedTo($uri, $with = []);• ->assertRedirectedToRoute($name, $parameters = [], $with = []);• ->assertRedirectedToAction($name, $parameters = [], $with = []);• ->assertSessionHas($key, $value = null);• ->assertSessionHasAll(array $bindings);• ->assertSessionHasErrors($bindings = [], $format = null);• ->assertHasOldInput();

Faking Data• https://github.com/fzaninotto/Faker• Allows us to not spend time making up test

data.

Example Form

Example Controller

Test Code – First Try

Problems?• Database is not cleaned up. We could use

seeding in our setup and teardown methods.• Email attempt adds a dependency upon a

network or cloud service.• Testing all the logic of the controller at once

makes problems hard to diagnose.

Laravel Can Help

• Disabling Middleware allows testing only your controller code• Wrapping test in a database transaction helps clean up• Using migrations allows for resetting database to consistent

state.

How we can help ourselves• DRY – Don’t Repeat Yourself – Be Lazy, write code once• Single Responsibility Object – No “Jack of all Trades” Objects• Dependency Injection – Give me what I need to do my job• Keep cyclomatic complexity low – If there is a fork in the road

take it• Law of Demeter – Don’t extend reach too far• Design Patterns – Somebody has already solved our problems

Improving Our Example

• Remove dependency on session

Rerun Test and See Failure

• Remove if (is_numeric(session($user_id)))

Dependency Injection• Pass in the objects you need• Code to interfaces• Avoid creating a “new” object.• Setter Injection v. Constructor Injection• Helps follow Law of Demeter

Arguments Against DI• Our dependencies won’t change• Too complex

Benefits of DI• Can now mock objects while testing• Test our code, not 3rd party libraries• Loose coupling allows for easier upgrades• Built in to Laravel

Let’s try it out• Laravel will inject an instance of a class that is type hinted in a

constructor or method.

• Now we can use our factory anywhere within our controller.

Controller is Much Skinnier

Mock objects allow for easy controller testing

• We create a mock PersonFactory and specify which methods will be called and what they should return.

• Our person creation logic is now moved to a single class (DRY), our controller can now be tested without a database.

• Yet to test our person factory we must still seed and clean up our database.

Repository Pattern• Separate getting the data from the data

object. • Code to an interface to allow for mocking.

Wrapper Around Class• Takes class doing work as parameter• Easy to Mock• Won’t use underlying resources, e.g. API, to

run test.

Mocking a Facade• The Mail class is a Laravel façade so we can

easily mock it like this.

• Laravel takes care of the rest for us.

Resources• http://martinfowler.com/eaaCatalog/tableDataGateway.html• https://www.youtube.com/watch?v=HhwElTL-mdI - Evan Dorn LA Ruby Meetup• https://www.youtube.com/watch?v=X6c11niH-U8 - Chris Hartjes Ski PHP• https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/• https://github.com/fzaninotto/Faker• http://laravelcoding.com/blog/laravel-5-beauty-testing• https://laravel.com/docs/5.1/testing• http://martinfowler.com/articles/mocksArentStubs.html

Thanks• Derek Binkley - @DerekB_WI or dbinkley@ncbex.org• Slides are at

http://www.slideshare.net/DerekBinkley/testing-with-laravel

• Feedback on Joind.in at https://joind.in/talk/dc052

top related