testing with laravel

31
Designing for Testability with Laravel Derek Binkley @DerekB_WI

Upload: derek-binkley

Post on 16-Apr-2017

510 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Testing with laravel

Designing for Testability with Laravel

Derek Binkley@DerekB_WI

Page 2: Testing with laravel

About Me★Lead Developer at National Conference of

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

Page 3: Testing with laravel

About NCBEExamining Bars?

Page 4: Testing with laravel

About NCBENo, developing the bar exam for future lawyers.

Plus, supporting state admission authorities.

Page 5: Testing with laravel

What will we cover?

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

Detailed examples

Page 6: Testing with laravel

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.

Page 7: Testing with laravel

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.

Page 8: Testing with laravel

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.

Page 9: Testing with laravel

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

run our controllers.

Page 10: Testing with laravel

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();

Page 11: Testing with laravel

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

data.

Page 12: Testing with laravel

Example Form

Page 13: Testing with laravel

Example Controller

Page 14: Testing with laravel

Test Code – First Try

Page 15: Testing with laravel

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.

Page 16: Testing with laravel

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.

Page 17: Testing with laravel

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

Page 18: Testing with laravel

Improving Our Example

• Remove dependency on session

Page 19: Testing with laravel

Rerun Test and See Failure

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

Page 20: Testing with laravel

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

Page 21: Testing with laravel

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

Page 22: Testing with laravel

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

Page 23: Testing with 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.

Page 24: Testing with laravel

Controller is Much Skinnier

Page 25: Testing with laravel

Mock objects allow for easy controller testing

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

Page 26: Testing with laravel

• 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.

Page 27: Testing with laravel

Repository Pattern• Separate getting the data from the data

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

Page 28: Testing with laravel

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

run test.

Page 29: Testing with laravel

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.

Page 30: Testing with laravel

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

Page 31: Testing with laravel

Thanks• Derek Binkley - @DerekB_WI or [email protected]• Slides are at

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

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