Tuesday, March 4, 2014

Behavior Driven Design and Testing

Behavior Driven Design (BDD) and testing is appropriate for Object Oriented Programming (OOP).

When designing a system using OOP, focus on designing object interfaces and interactions/messages and behaviors.

Messaging

  • Design how components components communicate (more than internal behaviors)
  • The meaning of the domain model (hence behavior) of a system is found in its messages
  • Change behavior of a system by object composition, rather than modifying internal logic
  • Encapsulate implementation using "tell don't ask" coding techniques
  • Rather than procedural getting info and making decisions from that to a telling based system
  • Hide internal state (allows you to build complex APIs that you don't need to know implementation of
  • See (and test) what objects do, not what it is
  • Assert on messages going between objects
  • Well designed objects do not know who they are talking to (only need to know their collaborators' Role

Single Responsibility Principle

  • An object should only have one reason to change

OOP Testing

  • When mocking Roles, TDD becomes a Design Process
  • Mock Roles (not objects)
  • When you assert on State you are Stubbing
  • Stubs return a value (and are never the focus of the test)
  • When you assert on Messages that go between Objects, you are Mocking
  • Use Mocks for OOP, not procedural code
  • Don't mock Boundary Objects
  • Let Integration Tests or Acceptance Tests handle boundary objects
  • Mock Peers (not internals)
  • Don't Mock or Stub implementation details
  • Use Stubs to avoid hitting a real server (ex: making 3rd party api call)
  • Test response state (ex: body of response) when object becomes complex
  • Generally, think in a Tell (don't Ask) style
  • Write some Integration tests to test hitting real server (to know if they broke the interface)
  • Mock objects verify the behavior of the system under test
  • Mock objects can have expectations (Stubs can't)
  • Mock objects' expectations form the specification of the calls they are expected to receive

OOP Testing Process

  • What is not internal to my object?
  • Come up with a Scenario that demonstrates Domain Logic of expected Behavior
  • What is the role that the collaborating object needs to play?
  • What behavior should I tell the collaborating object to do?
  • Assert on the message (not the state of an object)
  • Decide, What is inside and what is outside your object?

Results

  • Decoupled/Loosely Coupled System
  • Strong Separation of Concerns
  • Tests respect code Encapsulation
  • Use Mock objects to define Interfaces
  • Ease Code Management/Changes over time
  • High level modules which define interfaces that lower level modules implement
  • "You have to implement this interface for me to use you to do this job." (Details depend on Abstractions)
  • Removal of Dependencies
  • Inversion of Control (objects created outside class in which they are used)


References

http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627/ref=sr_1_1?ie=UTF8&qid=1393977301&sr=8-1&keywords=growing+object-oriented+software+guided+by+tests

http://jmock.org/oopsla2004.pdf

http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

http://www.slideshare.net/paskavatta/mo-dip-15104789

2 comments: