PHPUnit vs PHPSpec © Rudolf Horváth

Slides:



Advertisements
Similar presentations
SPL/2010 Test-Driven Development (TDD) 1. SPL/
Advertisements

xUnit Test Patterns (Some) xUnit Test Patterns (in practice) by Adam Czepil.
Integration Testing When testing a module in isolation –Called modules need to be replaced –Tested module needs to be called A D ′ E ′ main driver module.
JUnit, Revisited 17-Apr-17.
14-Jul-15 JUnit 4. Comparing JUnit 3 to JUnit 4 All the old assertXXX methods are the same Most things are about equally easy JUnit 4 makes it easier.
Programmer Testing Testing all things Java using JUnit and extensions.
Unit Testing & Defensive Programming. F-22 Raptor Fighter.
JUnit The framework. Goal of the presentation showing the design and construction of JUnit, a piece of software with proven value.
REFACTORING Lecture 4. Definition Refactoring is a process of changing the internal structure of the program, not affecting its external behavior and.
Polymorphism, Inheritance Pt. 1 COMP 401, Fall 2014 Lecture 7 9/9/2014.
Programming in Java Unit 2. Class and variable declaration A class is best thought of as a template from which objects are created. You can create many.
The Java Programming Language
CSCI-383 Object-Oriented Programming & Design Lecture 13.
Testing. 2 Overview Testing and debugging are important activities in software development. Techniques and tools are introduced. Material borrowed here.
Programming with Java © 2002 The McGraw-Hill Companies, Inc. All rights reserved. 1 McGraw-Hill/Irwin Chapter 5 Creating Classes.
JUnit Don Braffitt Updated: 10-Jun-2011.
How to Test Methods Computer Science 3 Gerb Objective: Test methods properly.
Unit Testing with FlexUnit
SourceAnatomy1 Java Source Anatomy Barb Ericson Georgia Institute of Technology July 2008.
Test Automation For Web-Based Applications Portnov Computer School Presenter: Ellie Skobel.
Google C++ Testing Framework Part 2: Assertion. Concepts A test case contains one or many tests. ◦ You should group your tests into test cases that reflect.
PHPUnit Julia Bondar IAPM23. Agenda What is PHPUnit How to write an automated test Writing and running tests with PHPUnit Advantages and disadvantages.
Today protected access modifier Using the debugger in Eclipse JUnit testing TDD Winter 2016CMPE212 - Prof. McLeod1.
Automated Testing with PHPUnit. How do you know your code works?
Chapter 5 Introduction to Defining Classes Fundamentals of Java.
The Object-Oriented Thought Process Chapter 03
Software Construction Lab 10 Unit Testing with JUnit
Unit Testing - solid fundamentals
TESTING TEST DRIVEN DEVELOPMENT
Working with Java.
Chapter 6 CS 3370 – C++ Functions.
Developer Testing Tricks
Eddie Jaquith Alexis Jarvis
More JUnit CS 4501 / 6501 Software Testing
Test Driven Development 1 November Agenda  What is TDD ?  Steps to start  Refactoring  TDD terminology  Benefits  JUnit  Mocktio  Continuous.
Chapter 8 – Software Testing
Testing and Debugging.
Debugging and Random Numbers
Coding Defensively Coding Defensively
Un</br>able’s MySecretSecrets
ATS Application Programming: Java Programming
COTS testing Tor Stålhane.
Selenium HP Web Test Tool Training
Unit testing C# classes
Subroutines Idea: useful code can be saved and re-used, with different data values Example: Our function to find the largest element of an array might.
Testing in PowerShell Powered by Pester NATHAN ZIEHNERT 5/25/2018.
History, Characteristics and Frameworks
Functions BIS1523 – Lecture 17.
DRUPAL CAMP NJ 2018 DRUPALCAMPNJ
The Object-Oriented Thought Process Chapter 05
What’s changed in the Shibboleth 1.2 Origin
Test-driven development (TDD)
Introduction to JUnit CS 4501 / 6501 Software Testing
Chapter 1: Computer Systems
Testing and debugging A short interlude 2-Dec-18.
Advanced Java Programming
PHP.
More Object-Oriented Programming
More JUnit CS 4501 / 6501 Software Testing
Defining Classes and Methods
Introduction to JUnit IT323 – Software Engineering II
Exception Handling Imran Rashid CTO at ManiWeber Technologies.
ECE 352 Digital System Fundamentals
Testing and debugging A short interlude 17-Apr-19.
Defining Classes and Methods
Computer Science 340 Software Design & Testing
CMPE212 – Reminders Assignment 2 due next Friday.
CMSC 202 Exceptions.
Review for Midterm 3.
Junit Tests.
Presentation transcript:

PHPUnit vs PHPSpec © Rudolf Horváth Unit Testing PHPUnit vs PHPSpec © Rudolf Horváth

Unit Testing The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and determine whether it behaves exactly as you expect. Each unit is tested separately before integrating them into modules to test the interfaces between modules.

A good test Able to be fully automated Has full control over all the pieces running (Use mocks or stubs to achieve this isolation when needed) Can be run in any order if part of many other tests Runs in memory (no DB or File access, for example) Consistently returns the same result (Typically no random numbers. Save those for integration or range tests) Runs fast Tests a single logical concept in the system Readable Maintainable Trustworthy (when you see its result, you don’t need to debug the code just to be sure)

PHPUnit The tests for a class Class go into a class ClassTest. ClassTest inherits (most of the time) from PHPUnit_Framework_TestCase. The tests are public methods that are named test*. Alternatively, you can use the @test annotation in a method's docblock to mark it as a test method. Inside the test methods, assertion methods such as assertEquals() are used to assert that an actual value matches an expected value.

Simple example

Test dependencies To quickly localize defects, we want our attention to be focussed on relevant failing tests. This is why PHPUnit skips the execution of a test when a depended-upon test has failed. This improves defect localization by exploiting the dependencies between tests. There can be multiple dependencies

Data Providers Must return Iterator, or arry

Testing Exceptions Or simply try {} catch and see if it’s there

Assertions assertArrayHasKey(mixed $key, array $array[, string $message = '']) assertContains(mixed $needle, Iterator|array $haystack[, string $message = '']) assertContainsOnly(string $type, Iterator|array $haystack[, boolean $isNativeType = NULL, string $message = '']) assertContainsOnlyInstancesOf(string $classname, Traversable|array $haystack[, string $message = '']) assertCount($expectedCount, $haystack[, string $message = '']) assertEmpty(mixed $actual[, string $message = '']) assertEquals(mixed $expected, mixed $actual[, string $message = '']) assertFalse(bool $condition[, string $message = '']) assertTrue(bool $condition[, string $message = '']) assertFileExists(string $filename[, string $message = '']) assertGreaterThan(mixed $expected, mixed $actual[, string $message = '']) assertGreaterThanOrEqual(mixed $expected, mixed $actual[, string $message = '']) assertInstanceOf($expected, $actual[, $message = '']) assertNull(mixed $variable[, string $message = '']) assertSame(mixed $expected, mixed $actual[, string $message = '']) Every assertion has a negative “Not” version with the same parameters

AssertThat

Fixtures

Fixtures setUp(), tearDown()once for each test method (and on fresh instances) of the test case class. setUpBeforeClass(), tearDownAfterClass()before the first test of the test case class is run and after the last test of the test case class is run, respectively. assertPreConditions() assertPostConditions() onNotSuccessfulTest() you only need to implement tearDown() if you have allocated external resources like files or sockets in setUp(). If your setUp() just creates plain PHP objects, you can generally ignore tearDown()

Let’s try those… Download previous lesson’s zip, launch mysql server composer require --dev phpunit/phpunit ^5.7 (6.1 is only for PHP 7+) Change files DataLoader.php (disable output), carService (allow null Request parameter) Change DefaultControllerTest to CarControllerTest Start CarServiceTest phpunit --tap

Test doubles Sometimes it is just plain hard to test the system under test (SUT) because it depends on other components that cannot be used in the test environment. This could be because they aren't available, they will not return the results needed for the test or because executing them would have undesirable side effects. In other cases, our test strategy requires us to have more control or visibility of the internal behavior of the SUT. When we are writing a test in which we cannot (or chose not to) use a real depended-on component (DOC), we can replace it with a Test Double. The Test Double doesn't have to behave exactly like the real DOC; it merely has to provide the same API as the real one so that the SUT thinks it is the real one!

Test doubles getMock($className) By default, all methods of the original class are replaced with a dummy implementation that just returns NULL (without calling the original method). Using the will($this->returnValue()) method, for instance, you can configure these dummy implementations to return a value when called. final, private and static methods cannot be stubbed or mocked. They retain their original behavior.

Stubs

Stubs (with MockBuilder)

Stubs (with MockBuilder) setConstructorArgs(array $args) setMockClassName($name) disableOriginalConstructor() disableOriginalClone() disableAutoload() any() once() never() atLeastOnce() exactly() at(index) returnValue() returnArgument() returnSelf() returnCallback() (throwException())

Code Coverage Code Coverage

Test Driven Development Drives out the functionality the software actually needs, rather than what the programmer thinks it probably ought to have When to write test? - Long after development - Shortly after development or - before? Problems (?): - When you first write the test it cannot possibly run - Feels strange at first (programming to an interface instead of programming to an implementation)

Behaviour-Driven Development Traditional TDD tools still force developers to think in terms of tests and assertions instead of specifications. It's about figuring out what you are trying to do before you run off half-cocked to try to do it. You write a specification that nails down a small aspect of behaviour in a concise, unambiguous, and executable form. It's all about specifying behaviour and not writing tests. Suddenly the idea of having a Test class for each of your production classes is ridiculously limiting. And the thought of testing each of your methods with its own test method (in a 1-1 relationship) will be laughable.

The other way

PHPSpec Test class names end with “Spec”. The spec extends the special ObjectBehavior class. This class is special, because it gives you ability to call all the methods of the class you are describing and match the result of the operations against your expectations. Method names are underscored, starting with “it_” or “its_”

Matchers Matchers are much like assertions, except the fact that matchers concentrate on telling how the object should behave instead of verifying how it works. Identity (return, be, equal, beEqualTo) it’s like checking === Comparison (beLike) it’s like checking == Throw (throw -> during) for testing exceptions Type (beAnInstanceOf, returnAnInstanceOf, haveType) checks object type ObjectState (have**) checks object is** method return value

Matchers

Identity matcher

Comparison matcher

Throw matcher

Type matcher

ObjectState matcher

Count matcher

Scalar matcher

Stubs - Prophecy $prophecy = $prophet->prophesize('MyClass'); $prophecy->read('123')->willReturn('value'); ReturnPromise [->willReturn(1)] returns a value from a method call ReturnArgumentPromise [->willReturnArgument()] returns the first method argument from call ThrowPromise [->willThrow] causes the method to throw specific exception CallbackPromise [->will($callback)] gives you a quick way to define your own custom logic Keep in mind, that you can always add even more promises by implementing Prophecy\Promise\PromiseInterface.

Stubs Method prophecy Argument wildcarding

Stubs - Argument wildcards ExactValueToken [Argument::exact($value)] checks that the argument matches a specific value TypeToken [Argument::type($typeOrClass)] checks that the argument matches a specific type or classname. ObjectStateToken [Argument::which($method, $value)] checks that the argument method returns a specific value CallbackToken [Argument::that(callback)] checks that the argument matches a custom callback AnyValueToken [Argument::any()] matches any argument AnyValuesToken [Argument::cetera()] matches any arguments to the rest of the signature

Mocks and call predictions $prophet->someMethod()->shouldBeCalled() CallPrediction [shouldBeCalled()] checks that the method has been called 1 or more times NoCallsPrediction [shouldNotBeCalled()] checks that the method has not been called CallTimesPrediction [shouldBeCalledTimes($count)] checks that the method has been called $count times CallbackPrediction [should($callback)] checks the method against your own custom callback Verify predictions with $prophet->checkPredictions();

Spies Prophecy records every call made during the double's entire lifetime. This means you don't need to record predictions in order to check them. You can also do it manually MethodProphecy::shouldHave(PredictionInterface $prediction)

let and letGo class MyMailingServiceSpec extends ObjectBehavior { public function let($mailer) $mailer->beAMockOf('\Swift_Mailer'); $this->beConstructedWith($mailer); } public function letgo() // release any resource // put the system back into the state it was