EECS 394 Software Project Management Chris Riesbeck Testing: BDD - - PowerPoint PPT Presentation

eecs 394 software project management
SMART_READER_LITE
LIVE PREVIEW

EECS 394 Software Project Management Chris Riesbeck Testing: BDD - - PowerPoint PPT Presentation

EECS 394 Software Project Management Chris Riesbeck Testing: BDD and Mock Objects Thursday, May 12, 2011 Behavior Driven Development Dan North evolved BDD from unit style TDD http://dannorth.net/introducing-bdd/ Test method names


slide-1
SLIDE 1

Chris Riesbeck

EECS 394 Software Project Management

Testing: BDD and Mock Objects

Thursday, May 12, 2011

slide-2
SLIDE 2

Behavior Driven Development

Dan North evolved BDD from unit style TDD

http://dannorth.net/introducing-bdd/

Test method names better as "should" sentences

testShouldFailForMissingSurname

Really about defining desired behaviors

self-testing is a secondary aspect

Behaviors derive ultimately from user stories:

As a [user] I want [feature] so that [benefit]

User story acceptance tests (scenarios):

Given some context,

When some event, then some outcomes should be true.

2

Thursday, May 12, 2011

slide-3
SLIDE 3

In unit testing framework

3

public class WindowControlBehavior { @Test public void shouldCloseWindows() { // Given WindowControl control = new WindowControl("My AFrame"); AFrame frame = new AFrame(); // When control.closeWindow(); // Then assert(!frame.isShowing()); } }

Thursday, May 12, 2011

slide-4
SLIDE 4

Tools for BDD

4

North created JBehave (Java) then RBehave (Ruby) RSpec (BDD for Ruby) incorporated RBehave

http://www.infoq.com/news/2007/10/RSpec-

incorporates-RBehave

Then Cucumber replaced RBehave

http://upstre.am/blog/2008/08/cucumber-next-

generation-rspec-story-runner/

https://github.com/aslakhellesoy/cucumber/wiki/

note the return of the "5 whys" halfway down

Main goal: make user acceptance tests readable,

less obscured by code details

Thursday, May 12, 2011

slide-5
SLIDE 5

Cucumber

5

A text-based story runner

written in Ruby for RSpec now supports Java, .Net, Flex and webapps Write acceptance tests in plain English Regular expression matching links text to code

http://cukes.info/ http://railscasts.com/episodes/155-beginning-with-

cucumber (15 minutes)

http://teachmetocode.com/screencasts/introduction-to-

  • utside-in-development-with-cucumber/ (25 minutes)

Thursday, May 12, 2011

slide-6
SLIDE 6

Fitnesse

6

Tests as decision tables in web pages

preceded Cucumber tests that client can read all-in-one server with wiki-based editor

  • riginally for Java, now many languages

http://fitnesse.org/

Thursday, May 12, 2011

slide-7
SLIDE 7

easyb

Story verification framework for Java using the

Groovy scripting language

http://www.easyb.org/

7

Thursday, May 12, 2011

slide-8
SLIDE 8

Levels of testing

Unit tests

test individual modules (methods, classes) should be numerous, fast, detailed, automated

System integration tests

test collections of communicating modules should include all major communication paths typically fewer and slower than unit tests integration failures should generate new unit tests

User acceptance tests

integration tests specified and run by client define essential functionality for entire system

8

Thursday, May 12, 2011

slide-9
SLIDE 9

Discussions about acceptance tests

http://blog.8thlight.com/articles/2011/4/26/10-

ways-to-do-acceptance-testing-wrong

http://jamesshore.com/Blog/The-Problems-With-

Acceptance-Testing.html

http://jamesshore.com/Blog/Alternatives-to-

Acceptance-Testing.html

9

Thursday, May 12, 2011

slide-10
SLIDE 10

Unit Test Problem

Unit tests

test individual modules (methods, classes) should be numerous, fast, detailed, automated should not cross module boundaries should test the unit, not other classes

How can you unit test code

that calls other code that may be very slow, e.g., database connections that may not exist yet

10

Thursday, May 12, 2011

slide-11
SLIDE 11

Unit testing

11

public class OrderStateTester extends TestCase { private static String TALISKER = "Talisker"; private Warehouse warehouse = new WarehouseImpl(); protected void setUp() throws Exception { warehouse.add(TALISKER, 50); } public void testOrderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50);

  • rder.fill(warehouse);

assertTrue(order.isFilled()); assertEquals(0, warehouse.getInventory(TALISKER)); } public void testOrderNotFilledIfNotEnoughInWarehouse() { Order order = new Order(TALISKER, 51);

  • rder.fill(warehouse);

assertFalse(order.isFilled()); assertEquals(50, warehouse.getInventory(TALISKER)); } }

http://martinfowler.com/articles/mocksArentStubs.html

we want to test Order but we have to create a Warehouse object modify it and test it

Thursday, May 12, 2011

slide-12
SLIDE 12

Solution: Mock objects

A mock object is

a stub that imitates an object needed by the code

being tested

a "tape recorder" that can verify that the mock object

was used as intended

Must have an interface for the object to be mocked Implementing mock objects by hand can be tedious

for classes with many methods

Mock libraries provide tools for making mocks in just

a few steps

12

Thursday, May 12, 2011

slide-13
SLIDE 13

jMock 1: using Mock class

13

public class OrderTester extends TestCase { private Warehouse warehouse = new WarehouseImpl(); ... public void testOrderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50);

  • rder.fill(warehouse);

assertTrue(order.isFilled()); assertEquals(0, warehouse.getInventory(TALISKER)); } public class OrderTester extends MockObjectTestCase { ... public void testOrderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50); Mock warehouseMock = new Mock(Warehouse.class); ...

  • rder.fill((Warehouse) warehouseMock.proxy());

assertTrue(order.isFilled()); warehouseMock.verify(); }

http://martinfowler.com/articles/mocksArentStubs.html

create a mock Warehouse verify the mock's expectations pass the mock to Order

Thursday, May 12, 2011

slide-14
SLIDE 14

jMock 1: using mock() method

14

public class OrderTester extends TestCase { private Warehouse warehouse = new WarehouseImpl(); ... public void testOrderNotFilledIfNotEnoughInWarehouse() { Order order = new Order(TALISKER, 51);

  • rder.fill(warehouse);

assertFalse(order.isFilled()); assertEquals(50, warehouse.getInventory(TALISKER)); } public class OrderTester extends MockObjectTestCase { ... public void testOrderNotFilledIfNotEnoughInWarehouse() { Order order = new Order(TALISKER, 51); Mock warehouse = mock(Warehouse.class); ...

  • rder.fill((Warehouse) warehouse.proxy());

assertFalse(order.isFilled()); }

http://martinfowler.com/articles/mocksArentStubs.html

defines mock() method mocked() objects are verified automatically when test finishes call mock() to make mocked object

Thursday, May 12, 2011

slide-15
SLIDE 15

jMock 1: setting expectations

15

http://martinfowler.com/articles/mocksArentStubs.html

public void testOrderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50); Mock warehouseMock = new Mock(Warehouse.class); warehouseMock.expects(once()).method("hasInventory") .with(eq(TALISKER),eq(50)) .will(returnValue(true)); warehouseMock.expects(once()).method("remove") .with(eq(TALISKER), eq(50)) .after("hasInventory");

  • rder.fill((Warehouse) warehouseMock.proxy());

warehouseMock.verify(); assertTrue(order.isFilled()); }

hasInventory(TALISKER, 50) should be called once, and will return true remove(TALISKER, 50) should be called once, after hasInventory() call expectations define the expected usage of mock

  • bject in a specific test

Thursday, May 12, 2011

slide-16
SLIDE 16

EasyMock 1: setting expectations

16

http://martinfowler.com/articles/mocksArentStubs.html

public class OrderEasyTester extends TestCase { ... private MockControl warehouseControl; private Warehouse warehouseMock; public void setUp() { warehouseControl = MockControl.createControl(Warehouse.class); warehouseMock = (Warehouse) warehouseControl.getMock(); } public void testOrderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50); warehouseMock.hasInventory(TALISKER, 50); warehouseControl.setReturnValue(true); warehouseMock.remove(TALISKER, 50); warehouseControl.replay();

  • rder.fill(warehouseMock);

warehouseControl.verify(); assertTrue(order.isFilled()); }

normal JUnit TestCase record and replay approach to setting expectations compiled method calls

Thursday, May 12, 2011

slide-17
SLIDE 17

jMock 2: generic API

17

public class OrderTester extends MockObjectTestCase { ... public void testOrderIsFilledIfEnoughInWarehouse() { final Order order = new Order(TALISKER, 50); final Warehouse warehouseMock = mock(Warehouse.class); checking(new Expectations() {{ final Sequence ordering = sequence("ordering");

  • neOf (warehouseMock).hasInventory(TALISKER, 50);

inSequence(ordering);

  • neOf (wareHouseMock).remove(TALISKER, 50);

inSequence(ordering); }}

  • rder.fill(warehouseMock);

assertTrue(order.isFilled()); }

with Java generics, no Mock class, no typecasting expectations stored in separate Expectations object Java Double-Brace initializer block sequences are

  • ptional and

separate objects

EasyMock 3.0 also has a generic API

Thursday, May 12, 2011

slide-18
SLIDE 18

Mock libraries

18

Ruby - list of options

http://www.ruby-toolbox.com/categories/mocking.html

PHP

SimpleTest includes a mocking API:

http://www.lastcraft.com/mock_objects_documentation.php

Mockery, usable with PHPUnit

http://blog.astrumfutura.com/2010/05/mockery-from-mock-

  • bjects-to-test-spies/

Python

Mocker -- uses record/replay approach

http://labix.org/mocker

Fudge - modeled on jMock

http://farmdev.com/projects/fudge/

Thursday, May 12, 2011