Welcome!

  New Features in PHPUnit 3.3




         Sebastian Bergmann
    http://sebastian-bergmann.de/




           J...
Who I am


           ●   Sebastian Bergmann
           ●   Involved in the
               PHP Project since 2000
        ...
PHPUnit


●   Test Framework
    –   Member of the xUnit family of test frameworks
    –   Mock Objects
    –   DbUnit
●  ...
Unit Tests with PHPUnit

<?php
require_once 'PHPUnit/Framework/TestCase.php';


class BowlingGameTest extends PHPUnit_Fram...
Unit Tests with PHPUnit

<?php
require_once 'PHPUnit/Framework/TestCase.php';


class BowlingGameTest extends PHPUnit_Fram...
Unit Tests with PHPUnit

<?php
require_once 'PHPUnit/Framework/TestCase.php';
require_once 'BowlingGame.php';

class Bowli...
Unit Tests with PHPUnit

<?php
require_once 'PHPUnit/Framework/TestCase.php';
require_once 'BowlingGame.php';

class Bowli...
Unit Tests with PHPUnit

<?php
require_once 'PHPUnit/Framework/TestCase.php';
require_once 'BowlingGame.php';

class Bowli...
Unit Tests with PHPUnit



    sb@vmware ~ % phpunit BowlingGameTest
    PHPUnit 3.3.0 by Sebastian Bergmann.

    .

    ...
Annotations
@assert
          <?php
          class Calculator
          {
              /**
               * @assert (1, ...
Annotations
@assert



          sb@vmware ~ % phpunit Calculator
          PHPUnit 3.3.0 by Sebastian Bergmann.

        ...
Annotations
@expectedException



<?php
class ExceptionTest extends PHPUnit_Framework_TestCase
{
    /**
     * @expectedE...
Annotations
@expectedException



    sb@vmware ~ % phpunit ExceptionTest
    PHPUnit 3.3.0 by Sebastian Bergmann.

    F
...
Annotations
@dataProvider
   <?php
   class DataTest extends PHPUnit_Framework_TestCase
   {
       /**
         * @dataPr...
Annotations
@dataProvider


sb@vmware ~ % phpunit DataTest
PHPUnit 3.3.0 by Sebastian Bergmann.

..F.

Time: 0 seconds

Th...
Annotations
@group
  <?php
  class SomeTest extends PHPUnit_Framework_TestCase
  {
      /**
       * @group specification...
Annotations
@group
    sb@vmware ~ % phpunit SomeTest
    PHPUnit 3.3.0 by Sebastian Bergmann.

    ..

    Time: 0 second...
Annotations
@test
<?php
class Specification extends PHPUnit_Framework_TestCase
{
    /**
     * @test
     */
    public f...
Annotations
@test




    sb@vmware ~ % phpunit --testdox Specification
    PHPUnit 3.3.0 by Sebastian Bergmann.

    Spec...
Behaviour-Driven Development


●   Extreme Programming originally had the rule to
    test everything that could possibly ...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

<?php
require_once 'PHPUnit/Extensions/Story/TestCase.php';
require_once 'BowlingGame.php';
...
Behaviour-Driven Development

sb@vmware ~ % phpunit --story BowlingGameSpec
PHPUnit 3.3.0 by Sebastian Bergmann.

BowlingG...
Generating Code from Tests

<?php
class BowlingGameTest extends PHPUnit_Framework_TestCase {
    protected $game;

    pro...
Generating Code from Tests

sb@vmware ~ % phpunit --skeleton-class BowlingGameTest
PHPUnit 3.3.0 by Sebastian Bergmann.

W...
Generating Code from Tests

<?php
class BowlingGameTest extends PHPUnit_Framework_TestCase {
    protected $game;

    pro...
Generating Code from Tests

<?php
class BowlingGameTest extends PHPUnit_Framework_TestCase {
    protected $game;

    pro...
Generating Code from Tests

<?php
class BowlingGameTest extends PHPUnit_Framework_TestCase {
    protected $game;

    pro...
Generating Code from Tests

<?php
class BowlingGameTest extends PHPUnit_Framework_TestCase {
    protected $game;

    pro...
Generating Code from Tests

<?php
class BowlingGameTest extends PHPUnit_Framework_TestCase {
    protected $game;

    pro...
Mock Objects
returnArgument()
<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnArgu...
Mock Objects
returnCallback()
<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnCall...
TextUI Testrunner
Counting of assertions
sb@vmware ~ % phpunit BowlingGameTest
PHPUnit 3.3.0 by Sebastian Bergmann.

.

Ti...
TextUI Testrunner
Colours!
sb@vmware ~ % phpunit --ansi BowlingGameTest
PHPUnit 3.3.0 by Sebastian Bergmann.

.

Time: 0 s...
TextUI Testrunner
Counting of assertions
sb@vmware ~ % phpunit BowlingGameTest
PHPUnit 3.3.0 by Sebastian Bergmann.

.F

T...
TextUI Testrunner
Colours!
sb@vmware ~ % phpunit --ansi BowlingGameTest
PHPUnit 3.3.0 by Sebastian Bergmann.

.F

Time: 0 ...
PHPUnit 3.3
Other new features


●   New assertions
    –   assertXmlFileTag(), assertXmlFileNotTag()
    –   assertXmlStr...
PHPUnit 3.3
Other new features


●   Mock Objects are faster
●   SeleniumTestCase supports verify*()
●   Feature and Memor...
PHPUnit 3.3
Backwards Compatibility Breaking Changes


●   Removed PHPUnit_Extensions_ExceptionTestCase
    –   Functional...
The End


●   Thank you for your interest!
●   These slides will be available shortly on
    http://sebastian-bergmann.de/...
License

    This presentation material is published under the Attribution-Share Alike 3.0 Unported
    license.
    You a...
Upcoming SlideShare
Loading in...5
×

New Features PHPUnit 3.3 - Sebastian Bergmann

3,119

Published on

Published in: Business, Technology
1 Comment
2 Likes
Statistics
Notes
  • Hi Sebastina Sir,
    Thanks For your 100% helpful stuff Regarding Unit Testing-Selenium. I am a Newbie in this TDD.
    So I expect more stuffs from you in future.
    Regards
    Anes P.A(anes.pa@gmail(dot)com)
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
3,119
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
57
Comments
1
Likes
2
Embeds 0
No embeds

No notes for slide

Transcript of "New Features PHPUnit 3.3 - Sebastian Bergmann"

  1. 1. Welcome! New Features in PHPUnit 3.3 Sebastian Bergmann http://sebastian-bergmann.de/ June 14th 2008
  2. 2. Who I am ● Sebastian Bergmann ● Involved in the PHP Project since 2000 ● Developer of PHPUnit ● Author, Consultant, Coach, Trainer
  3. 3. PHPUnit ● Test Framework – Member of the xUnit family of test frameworks – Mock Objects – DbUnit ● Integration – Selenium RC – phpUnderControl, CruiseControl, ... ● Even More Cool Stuff :-) – Code Coverage, Software Metrics, and “Mess Detection” – Test Database – Mutation Testing (GSoC07 project)
  4. 4. Unit Tests with PHPUnit <?php require_once 'PHPUnit/Framework/TestCase.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { }
  5. 5. Unit Tests with PHPUnit <?php require_once 'PHPUnit/Framework/TestCase.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { public function testScoreForOneSpareAnd3Is16() { } }
  6. 6. Unit Tests with PHPUnit <?php require_once 'PHPUnit/Framework/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { public function testScoreForOneSpareAnd3Is16() { $game = new BowlingGame; } }
  7. 7. Unit Tests with PHPUnit <?php require_once 'PHPUnit/Framework/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { public function testScoreForOneSpareAnd3Is16() { $game = new BowlingGame; $game->roll(5); $game->roll(5); $game->roll(3); for ($i = 4; $i <= 20; $i++) { $game->roll(0); } } }
  8. 8. Unit Tests with PHPUnit <?php require_once 'PHPUnit/Framework/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { public function testScoreForOneSpareAnd3Is16() { $game = new BowlingGame; $game->roll(5); $game->roll(5); $game->roll(3); for ($i = 4; $i <= 20; $i++) { $game->roll(0); } $this->assertEquals(16, $this->game->score()); } }
  9. 9. Unit Tests with PHPUnit sb@vmware ~ % phpunit BowlingGameTest PHPUnit 3.3.0 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 1 annotation)
  10. 10. Annotations @assert <?php class Calculator { /** * @assert (1, 2) == 3 */ public function add($a, $b) { return $a + $b; } /** * @assert (2, 1) == 1 */ public function sub($a, $b) { return $a - $b; } }
  11. 11. Annotations @assert sb@vmware ~ % phpunit Calculator PHPUnit 3.3.0 by Sebastian Bergmann. .. Time: 0 seconds OK (2 tests, 2 annotations)
  12. 12. Annotations @expectedException <?php class ExceptionTest extends PHPUnit_Framework_TestCase { /** * @expectedException InvalidArgumentException */ public function testException() { } }
  13. 13. Annotations @expectedException sb@vmware ~ % phpunit ExceptionTest PHPUnit 3.3.0 by Sebastian Bergmann. F Time: 0 seconds There was 1 failure: 1) testException(ExceptionTest) Expected exception InvalidArgumentException FAILURES! Tests: 1, Assertions: 0, Failures: 1.
  14. 14. Annotations @dataProvider <?php class DataTest extends PHPUnit_Framework_TestCase { /** * @dataProvider providerMethod */ public function testAdd($a, $b, $c) { $this->assertEquals($c, $a + $b); } public static function providerMethod() { return array( array(0, 0, 0), array(0, 1, 1), array(1, 1, 3), array(1, 0, 1) ); } }
  15. 15. Annotations @dataProvider sb@vmware ~ % phpunit DataTest PHPUnit 3.3.0 by Sebastian Bergmann. ..F. Time: 0 seconds There was 1 failure: 1) testAdd(DataTest) with data (1, 1, 3) Failed asserting that <integer:2> matches expected value <integer:3>. /home/sb/DataTest.php:19 FAILURES! Tests: 4, Assertions:4, Failures: 1.
  16. 16. Annotations @group <?php class SomeTest extends PHPUnit_Framework_TestCase { /** * @group specification */ public function testSomething() { } /** * @group regresssion * @group bug2204 */ public function testSomethingElse() { } }
  17. 17. Annotations @group sb@vmware ~ % phpunit SomeTest PHPUnit 3.3.0 by Sebastian Bergmann. .. Time: 0 seconds OK (2 tests, 2 annotations) sb@vmware ~ % phpunit --group bug2204 SomeTest PHPUnit 3.3.0 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 1 annotation)
  18. 18. Annotations @test <?php class Specification extends PHPUnit_Framework_TestCase { /** * @test */ public function shouldDoSomething() { } /** * @test */ public function shouldDoSomethingElse() { } }
  19. 19. Annotations @test sb@vmware ~ % phpunit --testdox Specification PHPUnit 3.3.0 by Sebastian Bergmann. Specification [x] Should do something [x] Should do something else
  20. 20. Behaviour-Driven Development ● Extreme Programming originally had the rule to test everything that could possibly break ● Now, however, the practice of testing in Extreme Programming has evolved into Test-Driven Development ● But the tools still force developers to think in terms of tests and assertions instead of specifications A New Look At Test-Driven Development, Dave Astels. http://blog.daveastels.com/files/BDD_Intro.pdf
  21. 21. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { }
  22. 22. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { /** * @scenario */ public function scoreForOneSpareAnd3Is16() { } // ... }
  23. 23. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { /** * @scenario */ public function scoreForOneSpareAnd3Is16() { $this->given('New game') } // ... }
  24. 24. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { /** * @scenario */ public function scoreForOneSpareAnd3Is16() { $this->given('New game') ->when('Player rolls', 5) } // ... }
  25. 25. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { /** * @scenario */ public function scoreForOneSpareAnd3Is16() { $this->given('New game') ->when('Player rolls', 5) ->and('Player rolls', 5) } // ... }
  26. 26. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { /** * @scenario */ public function scoreForOneSpareAnd3Is16() { $this->given('New game') ->when('Player rolls', 5) ->and('Player rolls', 5) ->and('Player rolls', 3) } // ... }
  27. 27. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { /** * @scenario */ public function scoreForOneSpareAnd3Is16() { $this->given('New game') ->when('Player rolls', 5) ->and('Player rolls', 5) ->and('Player rolls', 3) ->then('Score should be', 16); } // ... }
  28. 28. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { // ... public function runGiven(&$world, $action, $arguments) { switch($action) { case 'New game': { $world['game'] = new BowlingGame; $world['rolls'] = 0; } break; default: { return $this->notImplemented($action); } } } }
  29. 29. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { // ... public function runWhen(&$world, $action, $arguments) { switch($action) { case 'Player rolls': { $world['game']->roll($arguments[0]); $world['rolls']++; } break; default: { return $this->notImplemented($action); } } } }
  30. 30. Behaviour-Driven Development <?php require_once 'PHPUnit/Extensions/Story/TestCase.php'; require_once 'BowlingGame.php'; class BowlingGameSpec extends PHPUnit_Extensions_Story_TestCase { // ... public function runThen(&$world, $action, $arguments) { switch($action) { case 'Score should be': { for ($i = $world['rolls']; $i < 20; $i++) { $world['game']->roll(0); } $this->assertEquals($arguments[0], $world['game']->score()); } break; default: { return $this->notImplemented($action); } } } }
  31. 31. Behaviour-Driven Development sb@vmware ~ % phpunit --story BowlingGameSpec PHPUnit 3.3.0 by Sebastian Bergmann. BowlingGameSpec - Score for one spare and 3 is 16 [successful] Given New game When Player rolls 5 and Player rolls 5 and Player rolls 3 Then Score should be 16 Scenarios: 1, Failed: 0, Skipped: 0, Incomplete: 0. sb@vmware ~ % phpunit --testdox BowlingGameSpec PHPUnit 3.3.0 by Sebastian Bergmann. BowlingGameSpec [x] Score for one spare and 3 is 16
  32. 32. Generating Code from Tests <?php class BowlingGameTest extends PHPUnit_Framework_TestCase { protected $game; protected function setUp() { $this->game = new BowlingGame; } protected function rollMany($n, $pins) { for ($i = 0; $i < $n; $i++) { $this->game->roll($pins); } } public function testScoreForGutterGameIs0() { $this->rollMany(20, 0); $this->assertEquals(0, $this->game->score()); } }
  33. 33. Generating Code from Tests sb@vmware ~ % phpunit --skeleton-class BowlingGameTest PHPUnit 3.3.0 by Sebastian Bergmann. Wrote skeleton for quot;BowlingGamequot; to quot;BowlingGame.phpquot;. <?php class BowlingGame { /** * @todo Implement roll(). */ public function roll() { // Remove the following line when you implement this method. throw new RuntimeException('Not yet implemented.'); } /** * @todo Implement score(). */ public function score() { // Remove the following line when you implement this method. throw new RuntimeException('Not yet implemented.'); } } ?>
  34. 34. Generating Code from Tests <?php class BowlingGameTest extends PHPUnit_Framework_TestCase { protected $game; protected function setUp() { $this->game = new BowlingGame; } protected function rollMany($n, $pins) { for ($i = 0; $i < $n; $i++) { $this->game->roll($pins); } } public function testScoreForGutterGameIs0() { $this->rollMany(20, 0); $this->assertEquals(0, $this->game->score()); } }
  35. 35. Generating Code from Tests <?php class BowlingGameTest extends PHPUnit_Framework_TestCase { protected $game; protected function setUp() { $this->game = new BowlingGame; } protected function rollMany($n, $pins) { for ($i = 0; $i < $n; $i++) { $this->game->roll($pins); } } public function testScoreForGutterGameIs0() { $this->rollMany(20, 0); $this->assertEquals(0, $this->game->score()); } }
  36. 36. Generating Code from Tests <?php class BowlingGameTest extends PHPUnit_Framework_TestCase { protected $game; protected function setUp() { $this->game = new BowlingGame; } protected function rollMany($n, $pins) { for ($i = 0; $i < $n; $i++) { $this->game->roll($pins); } } public function testScoreForGutterGameIs0() { $this->rollMany(20, 0); $this->assertEquals(0, $this->game->score()); } }
  37. 37. Generating Code from Tests <?php class BowlingGameTest extends PHPUnit_Framework_TestCase { protected $game; protected function setUp() { $this->game = new BowlingGame; } protected function rollMany($n, $pins) { for ($i = 0; $i < $n; $i++) { $this->game->roll($pins); } } public function testScoreForGutterGameIs0() { $this->rollMany(20, 0); $this->assertEquals(0, $this->game->score()); } }
  38. 38. Generating Code from Tests <?php class BowlingGameTest extends PHPUnit_Framework_TestCase { protected $game; protected function setUp() { $this->game = new BowlingGame; } protected function rollMany($n, $pins) { for ($i = 0; $i < $n; $i++) { $this->game->roll($pins); } } public function testScoreForGutterGameIs0() { $this->rollMany(20, 0); $this->assertEquals(0, $this->game->score()); } }
  39. 39. Mock Objects returnArgument() <?php class StubTest extends PHPUnit_Framework_TestCase { public function testReturnArgumentStub() { $stub = $this->getMock( 'SomeClass', array('doSomething') ); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnArgument(1)); // $stub->doSomething('foo') returns 'foo' // $stub->doSomething('bar') returns 'bar' } }
  40. 40. Mock Objects returnCallback() <?php class StubTest extends PHPUnit_Framework_TestCase { public function testReturnCallbackStub() { $stub = $this->getMock( 'SomeClass', array('doSomething') ); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnCallback('callback')); // $stub->doSomething() returns callback(...) } } function callback() { $args = func_get_args(); // ... }
  41. 41. TextUI Testrunner Counting of assertions sb@vmware ~ % phpunit BowlingGameTest PHPUnit 3.3.0 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 1 assertions)
  42. 42. TextUI Testrunner Colours! sb@vmware ~ % phpunit --ansi BowlingGameTest PHPUnit 3.3.0 by Sebastian Bergmann. . Time: 0 seconds 1 OK (1 test, 0 assertions)
  43. 43. TextUI Testrunner Counting of assertions sb@vmware ~ % phpunit BowlingGameTest PHPUnit 3.3.0 by Sebastian Bergmann. .F Time: 0 seconds There was 1 failure: 1) testAllOnes(BowlingGameTest) Failed asserting that <integer:0> matches expected value <integer:20>. /home/sb/BowlingGameTest.php:25 FAILURES! Tests: 2, Assertions: 2, Failures: 1.
  44. 44. TextUI Testrunner Colours! sb@vmware ~ % phpunit --ansi BowlingGameTest PHPUnit 3.3.0 by Sebastian Bergmann. .F Time: 0 seconds There was 1 failure: 1) testAllOnes(BowlingGameTest) Failed asserting that <integer:0> matches expected value <integer:20>. /home/sb/BowlingGameTest.php:25 FAILURES! Tests: 1, Failures: 1.2, Failures: 1. 2, Assertions:
  45. 45. PHPUnit 3.3 Other new features ● New assertions – assertXmlFileTag(), assertXmlFileNotTag() – assertXmlStringTag(), assertXmlStringNotTag() – assertXmlFileSelect(), assertXmlStringSelect() – assertEqualXMLStructure() ● Changes to existing assertions – EOL canonicalization for ● assertEquals(), assertNotEquals(), ● assertFileEquals(), assertFileNotEquals() ● PHPUnit_Util_ErrorHandler::getErrorStack()
  46. 46. PHPUnit 3.3 Other new features ● Mock Objects are faster ● SeleniumTestCase supports verify*() ● Feature and Memory Performance improvements for the code coverage reporting
  47. 47. PHPUnit 3.3 Backwards Compatibility Breaking Changes ● Removed PHPUnit_Extensions_ExceptionTestCase – Functionality had been merged into PHPUnit_Framework_TestCase in PHPUnit 3.2 – Marked as deprecated in PHPUnit 3.2 ● Removed PHPUnit_Extensions_TestSetup – Functionality had been merged into PHPUnit_Framework_TestSuite in PHPUnit 3.2 – Marked as deprecated in PHPUnit 3.2
  48. 48. The End ● Thank you for your interest! ● These slides will be available shortly on http://sebastian-bergmann.de/talks/.
  49. 49. License   This presentation material is published under the Attribution-Share Alike 3.0 Unported license.   You are free: ✔ to Share – to copy, distribute and transmit the work. ✔ to Remix – to adapt the work.   Under the following conditions: ● Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). ● Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.   For any reuse or distribution, you must make clear to others the license terms of this work.   Any of the above conditions can be waived if you get permission from the copyright holder.   Nothing in this license impairs or restricts the author's moral rights.
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×