Testing in Practice
Total Page:16
File Type:pdf, Size:1020Kb
www.phparch.com April 2018 Volume 17 - Issue 4 Testing in Practice PHPUnit Worst Practices Easier Mocking with Mockery Testing Strategy With the Help of Static Analysis Evolved PHP ALSO INSIDE Artisanal: Community Corner: Education Station: Authentication with What’s the Fuss About Build an API, Part One Laravel Serverless? finally{}: The Dev Lead Trenches: Security Corner: On the Creativity of Ongoing Education PHP Isolation in Programmers Production PHP ApplicationSample Hosting PHP[TEK] 2018 The Premier PHP Conference 13th Annual Edition MAY 31ST – JUNE 1ST Downtown Atlanta Full scheduleSample announced! Talks from experts at MailChimp, Salesforce, Etsy, Google, Oracle, Pantheon and many more! tek.phparch.com APRIL 2018 Volume 17 - Issue 4 Features Columns 2 Editorial: Testing in Practice 3 PHPUnit Worst Practices Oscar Merida Victor Bolshov 27 Artisanal: Authentication with Laravel Joe Ferguson 8 Easier Mocking with 31 The Dev Lead Trenches: Ongoing Education Mockery, Part 1 Chris Tankersley Robert Basic 34 Security Corner: PHP Isolation in Production Eric Mann 14 Testing Strategy With the 36 Education Station: Build an API, Part One Help of Static Analysis Edward Barnard 44 March Happenings Ondrej Mirtes 46 Community Corner: Sample What’s the Fuss About 20 Evolved PHP Serverless? James Titcumb Chris Pitt 48 finally{}: On the Creativity of Programmers Eli White Editor-in-Chief: Subscriptions Although all possible care has been placed in assuring the Oscar Merida Print, digital, and corporate subscriptions are available. Visit accuracy of the contents of this magazine, including all https://www.phparch.com/magazine to subscribe or email associated source code, listings and figures, the publisher Editor: Kara Ferguson [email protected] for more information. assumes no responsibilities with regards of use of the information contained herein or in all associated material. Advertising To learn about advertising and receive the full prospectus, php[architect], php[a], the php[architect] logo, musketeers. contact us at [email protected] today! me, LLC and the musketeers.me, LLC logo are trademarks of musketeers.me, LLC. Managing Partners Kevin Bruce, Oscar Merida, Sandy Smith Contact Information: General mailbox: [email protected] php[architect] is published twelve times a year by: Editorial: [email protected] musketeers.me, LLC 201 Adams Avenue Print ISSN 1709-7169 Alexandria, VA 22301, USA Digital ISSN 2375-3544 Copyright © 2018—musketeers.me, LLC All Rights Reserved FEATURE Testing Strategy With the Help of Static Analysis Ondrej Mirtes When developing an application, our aim as software developers is to make sure it does what it ought to do and to keep the number of defects as low as possible. We should also strive to make our lives easier, to counter external circumstances like tight deadlines and ever-changing requirements causing the exact opposite. That’s why we’re always looking out for tools and practices to help us with our jobs. In this article, I’d like to introduce you to the concept of type safety and how it can improve the reliability and stability of your code. Once your code is more type-safe, and that fact is verified by automated tools, you can cherry-pick which parts of your application need extensive unit tests and where you can rely just on well-defined types. Type System And Type Safety additional benefits—not only that we know what we can pass to the function, it also tells us what operations (methods) the To have a type system means to communicate what kinds object offers. of values travel through code clearly. Since not all values can I’m not saying scalar values are never enough, and you be treated the same, the more we know about them, the better. should always use objects, but every time you’re tempted If you currently don’t have any type hints at all, adding infor- to type hint a string, go through a mental exercise on what mation to the code whether you’re accepting int, float, string could go wrong with the input. Do I want to allow an empty or bool can go a long way. string? What about non-ASCII characters? Instead of putting But when a function declares it accepts an integer, does validation logic into a function that does something with a it really mean any integer? Just a positive integer? Or only scalar value, create a special object and put the validation a limited set of values, like hours in a day or minutes in an logic in its constructor. You don’t have to write the valida- hour? Trimming down possible inputs reduces undefined tion in each place where the object is accepted anymore, and behavior. Going down this road further means you have you also don’t have to test the function’s behavior for inval- to start type-hinting your own objects which comes with id inputs provided the object cannot be created with invalid Samplevalues. Listing 1 For example, you might have a function which accepts a 1. class EmailAddress string for an email address, but you must check if the email 2. { is valid. 3. /** @var string */ function sendMessage(string $email) { 4. private $email; if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { 5. throw new \InvalidArgumentException( 6. public function __construct(string $email) { "Invalid email string" 7. if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { ); 8. throw new \InvalidArgumentException( } 9. "Not a valid email string" // do something 10. ); } 11. } 12. $this->email = $email; Instead, you can flip it and make your function—and any 13. } other one—explicitly expect an EmailAddress object as in 14. Listing 1. 15. public function getAddress(): string { 16. return $this->email; Once your codebase is filled with type hints, IDEs and stat- 17. } ic analyzers know more about it, and you can benefit from 18. } them. For example, if you annotate a property with a phpDoc 19. (unfortunately there’s no native support for property types 20. function sendMessage(EmailAddress $email) { yet), these tools can verify: 21. // do something 22. } 14 \ April 2018 \ www.phparch.com Testing Strategy With the Help of Static Analysis 1. The type hint is valid, and the class There’s no machine-readablephpDoc conventions, employ custom exists. connection between hasAddress() and plugins and analyze loops and branches 2. You’re assigning only objects of this getAddress() in type hints. The knowl- to infer as many types as possible. type to it. edge the above code will always work One of these tools is PHPStan1; it’s 3. You’re calling only methods avail- is available only in developer’s head or open-source and free to use (disclaim- able on the type-hinted class. by closely inspecting the source code er: I’m the main developer of PHPStan.) of the class. You might object that this Other similar tools are Phan2, Exakat3, /** example is too simple, and everyone 4 * @var Address and Psalm . understands what’s going on, but there */ Besides obvious errors, it can also are much more complex examples like private $address; point out code that can be simplified this in the wild. For example, a Product like always false comparisons using object that has every property nullable The same benefits stemming from ===, !==, instanceof, or isset() on because they can be empty while the type hints are also applicable to func- never defined variables, duplicate keys Product is being configured in the tion/method parameters and return in literal arrays, unused constructor content management system, but once types. There’s always the write part parameters, and much more. Because it’s published and available for purchase (what is returned from a method) and running a comprehensive analysis on on the site, they are guaranteed to be the read part (what the caller does with an existing codebase for the first time filled out. Any code that works only the returned value). can result in an overwhelming list of with published products has to make potential issues, PHPStan supports $value !== null checks in order to Listen to the Types gradual checking. Its goal is to enable comply with the type system. Types can also give you subtle developers to start using the tool as feedback about the design of your A solution to this problem is gener- soon as possible and to feel like they’re application—learn to listen to it. One ally not to reuse objects for different leveling up in a video game. use cases. You can represent published such case is inappropriate interfac- vendor/bin/phpstan analyse src/ es—when you’re implementing an products with a PublishedProduct class interface, and you’re forced to throw where every getter is non-nullable. If you run the PHPStan executable an exception from half of the methods without any flags, it will run the basic you have to add to the class, the inter- Tools for Finding Type level zero by default, checking only face isn’t designed well and will usually System Defects (a.K.a. types it’s completely sure about, like benefit from separating into several Bugs) methods called statically and on $this. smaller ones. Using such an interface It does not even check types passed to in production code is dangerous—by Because it is interpreted at runtime, method arguments until level five (only implementing it, you’re promising it’s PHP itself does not discover type the number of passed arguments is safe to pass the object somewhere the system defects in advance because that’s checked on lower levels), but it definite- interface is type-hinted but calling its usually a job of the compiler. A program ly finds a lot of issues in between. methods will throw unexpected excep- Samplein C# or Java will refuse to execute if PHPStan is extensible—you can there’s a problem like an undefined tions.