Chris Riesbeck
EECS 394 Software Project Management
Testing: BDD and Mock Objects
Thursday, May 12, 2011
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
Chris Riesbeck
Thursday, May 12, 2011
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,
2
Thursday, May 12, 2011
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
4
North created JBehave (Java) then RBehave (Ruby) RSpec (BDD for Ruby) incorporated RBehave
http://www.infoq.com/news/2007/10/RSpec-
Then Cucumber replaced RBehave
http://upstre.am/blog/2008/08/cucumber-next-
https://github.com/aslakhellesoy/cucumber/wiki/
note the return of the "5 whys" halfway down
Main goal: make user acceptance tests readable,
Thursday, May 12, 2011
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-
Thursday, May 12, 2011
6
Tests as decision tables in web pages
preceded Cucumber tests that client can read all-in-one server with wiki-based editor
http://fitnesse.org/
Thursday, May 12, 2011
Story verification framework for Java using the
http://www.easyb.org/
7
Thursday, May 12, 2011
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
http://blog.8thlight.com/articles/2011/4/26/10-
http://jamesshore.com/Blog/The-Problems-With-
http://jamesshore.com/Blog/Alternatives-to-
9
Thursday, May 12, 2011
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
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);
assertTrue(order.isFilled()); assertEquals(0, warehouse.getInventory(TALISKER)); } public void testOrderNotFilledIfNotEnoughInWarehouse() { Order order = new Order(TALISKER, 51);
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
A mock object is
a stub that imitates an object needed by the code
a "tape recorder" that can verify that the mock object
Must have an interface for the object to be mocked Implementing mock objects by hand can be tedious
Mock libraries provide tools for making mocks in just
12
Thursday, May 12, 2011
13
public class OrderTester extends TestCase { private Warehouse warehouse = new WarehouseImpl(); ... public void testOrderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50);
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); ...
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
14
public class OrderTester extends TestCase { private Warehouse warehouse = new WarehouseImpl(); ... public void testOrderNotFilledIfNotEnoughInWarehouse() { Order order = new Order(TALISKER, 51);
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); ...
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
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");
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
Thursday, May 12, 2011
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();
warehouseControl.verify(); assertTrue(order.isFilled()); }
normal JUnit TestCase record and replay approach to setting expectations compiled method calls
Thursday, May 12, 2011
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");
inSequence(ordering);
inSequence(ordering); }}
assertTrue(order.isFilled()); }
with Java generics, no Mock class, no typecasting expectations stored in separate Expectations object Java Double-Brace initializer block sequences are
separate objects
Thursday, May 12, 2011
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-
Python
Mocker -- uses record/replay approach
http://labix.org/mocker
Fudge - modeled on jMock
http://farmdev.com/projects/fudge/
Thursday, May 12, 2011