Junit-contracts: A Contract Testing Tool Claude N. Warren, Jr. - - PowerPoint PPT Presentation

junit contracts a contract testing tool
SMART_READER_LITE
LIVE PREVIEW

Junit-contracts: A Contract Testing Tool Claude N. Warren, Jr. - - PowerPoint PPT Presentation

Junit-contracts: A Contract Testing Tool Claude N. Warren, Jr. CloudStack Collaboration Conference Europe October 8-9, 2015 Dublin, Ireland Who Is Claude Warren? claude@xenei.com Apache Jena Project Management Committee Member and


slide-1
SLIDE 1

Junit-contracts: A Contract Testing Tool

Claude N. Warren, Jr. CloudStack Collaboration Conference Europe October 8-9, 2015 Dublin, Ireland

slide-2
SLIDE 2

Who Is Claude Warren?

  • claude@xenei.com
  • Apache Jena Project Management Committee

Member and Committer.

  • https://github.com/Claudenw
  • Playing with java since version 0.8
  • Developer/Architect > 25 years experience
  • Currently employed by IBM (Galway, IE)
  • Formerly employed by Digital Enterprise Research Institute

(Galway, IE), National Renewable Energy Laboratory (Golden, CO, USA)

  • Founding member of the Denver Area Mad Scientists Club
  • Winner of the first Critter Crunch (Robotics Competition)
  • Frustrated Musician
  • Author of Junit Contract test extension.
slide-3
SLIDE 3

What is Contract Testing

  • A Java interface outlines a contract.
slide-4
SLIDE 4

What is Contract Testing

  • A Java interface outlines a contract.
  • The contract is further refined and defined in other

documentation.

slide-5
SLIDE 5

What is Contract Testing

  • A Java interface outlines a contract.
  • The contract is further refined and defined in other

documentation.

  • Contract testing ensures that all testable facets of the

contract are tested.

slide-6
SLIDE 6

What is Contract Testing

  • A Java interface outlines a contract.
  • The contract is further refined and defined in other

documentation.

  • Contract testing ensures that all testable facets of the

contract are tested.

  • A jUnit extension written by Claude Warren and found at

https://github.com/Claudenw/junit-contracts

slide-7
SLIDE 7

Why Contract Testing

  • Verify that implementations are correct.

– Support can ask for proof of correctness of 2nd or 3rd

party implementations.

– Internal development teams can ensure that they are

correctly implementing the interface long before integration test.

  • Apply DRY (Don't Repeat Yourself) principles to interface
  • testing. One test covers all implementations.

– A class can have multiple interfaces but only one

parent, so consistent testing across implementations is difficult.

slide-8
SLIDE 8

Problem

public interface Foo { // Add an object. Implementations must log action. public void add( Object x ); Public boolean contains( Object x ); // register a logger to listen. Multiple calls ok. public void register( Logger log ); }

slide-9
SLIDE 9

Problem

public interface Foo { // Add an object. Implementations must log action. public void add( Object x ); Public boolean contains( Object x ); // register a logger to listen. Multiple calls ok. public void register( Logger log ); }

slide-10
SLIDE 10

Problem

public interface Foo { // Add an object. Implementations must log action. public void add( Object x ); Public boolean contains( Object x ); // register a logger to listen. Multiple calls ok. public void register( Logger log ); }

How do you verify that all implementations adhere to the logging requirement?

slide-11
SLIDE 11

Problem

public interface Foo { // Add an object. Implementations must log action. public void add( Object x ); Public boolean contains( Object x ); // register a logger to listen. Multiple calls ok. public void register( Logger log ); }

How do you verify that all implementations adhere to the logging requirement? How do you find all the implementations?

slide-12
SLIDE 12

Solution

  • Define a “producer” that provides the instance of the

interface.

slide-13
SLIDE 13

Solution

  • Define a “producer” that provides the instance of the

interface.

  • Define a concrete contract test that tests the instance

returned by a “producer”

slide-14
SLIDE 14

Solution

  • Define a “producer” that provides the instance of the

interface.

  • Define a concrete contract test that tests the instance

returned by a “producer”

  • Define a jUnit extension that locates all the contract tests,

associates them with the interface they test and locates all the classes that implement that interface.

slide-15
SLIDE 15

Producer Interface

public interface IProducer<T>() { public T newInstance(); public void cleanUp(); };

slide-16
SLIDE 16

Solution Diagram

Foo FooImpl1

slide-17
SLIDE 17

Solution Diagram

Foo Foo_CT @Contract(Foo.class) FooImpl1

slide-18
SLIDE 18

Solution Diagram

Foo Foo_CT @Contract(Foo.class) FooImpl1 FooImpl1_CS @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class)

slide-19
SLIDE 19

@Contract

@Contract(Foo.class) public class Foo_CT<T extends Foo> { private IProducer<T> fooProducer; @Contract.Inject public final void setFooContractTestProducer(IProducer<T> fooProducer) { this.fooProducer = fooProducer; } @ContractTest public void testAdd() { TestingLogger logger = … Object testObject = … Foo foo = fooProducer.newInstance(); foo.register( logger ); foo.add( testObject ); assertTrue( logger.recordedAdd() ); assertTrue( foo.contains( testObject ) ); } @After public void cleanup() { fooProducer.cleanUp(); } … }

Foo Foo_CT

slide-20
SLIDE 20

@ContractImpl(FooImpl1.class)

@RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) public class FooImpl1_CS { private IProducer<FooImpl1> fooProducer; public FooImpl1_CS() { fooProducer = new IProducer<FooImpl1>() { @Override public FooImpl1 newInstance() { return new FooImpl1(); } @Override public void cleanUp() { // nothing to do } }; } @Contract.Inject public final IProducer<FooImpl1> getTestProducer() { return fooProducer; } }

FooImpl1 FooImpl1_CS

slide-21
SLIDE 21

Runtime Result

FooImpl1 FooImpl1_CS @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) 1.Find class specified in ContractImpl

slide-22
SLIDE 22

Runtime Result

Foo FooImpl1 FooImpl1_CS @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) 1.Find class specified in ContractImpl 2.Find all ancestors of the class that are interfaces.

slide-23
SLIDE 23

Runtime Result

Foo Foo_CT FooImpl1 FooImpl1_CS @Contract(Foo.class) @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) 1.Find class specified in ContractImpl 2.Find all ancestors of the class that are interfaces. 3.Find all classes annotated with Contract and which test an ancestor interface.

slide-24
SLIDE 24

Runtime Result

Foo Foo_CT FooImpl1 FooImpl1_CS @Contract(Foo.class) @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) 1.Find class specified in ContractImpl 2.Find all ancestors of the class that are interfaces. 3.Find all classes annotated with Contract and which test an ancestor interface. 4.Instantiate each class found in step 3.

slide-25
SLIDE 25

Runtime Result

Foo Foo_CT FooImpl1 FooImpl1_CS @Contract(Foo.class) @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) 1.Find class specified in ContractImpl 2.Find all ancestors of the class that are interfaces. 3.Find all classes annotated with Contract and which test an ancestor interface. 4.Instantiate each class found in step 3. 5.Create a jUnit suite comprising all ContractTest annotated methods found in the class from step 3.

slide-26
SLIDE 26

Runtime Result

Foo Foo_CT FooImpl1 FooImpl1_CS @Contract(Foo.class) @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) 1.Find class specified in ContractImpl 2.Find all ancestors of the class that are interfaces. 3.Find all classes annotated with Contract and which test an ancestor interface. 4.Instantiate each class found in step 3. 5.Create a jUnit suite comprising all ContractTest annotated methods found in the class from step 3. 6.Get the Producer object from the contract suite and insert in class instantiated in step 4.

slide-27
SLIDE 27

Runtime Result

Foo Foo_CT FooImpl1 FooImpl1_CS @Contract(Foo.class) @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) 1.Find class specified in ContractImpl 2.Find all ancestors of the class that are interfaces. 3.Find all classes annotated with Contract and which test an ancestor interface. 4.Instantiate each class found in step 3. 5.Create a jUnit suite comprising all ContractTest annotated methods found in the class from step 3. 6.Get the Producer object from the contract suite and insert in class instantiated in step 4. 7.Execute the suite.

slide-28
SLIDE 28

Complex Solution Diagram

Foo Foo_CT FooImpl1 FooImpl1_CS @Contract(Foo.class) @RunWith(ContractSuite.class) @ContractImpl(FooImpl1.class) Bar Bar_CT @Contract(Bar.class)

slide-29
SLIDE 29

Who Benefits

  • SPI/API Implementers – Insure full implementation.
  • SPI/API Definers – Insure that other teams correctly

implement contracts.

  • QA Test – can easily validate that contracts are correctly

implemented.

  • QA Test Managers – can easily determine which contract

tests need to be developed or implemented.

slide-30
SLIDE 30

Bits and Bobs

  • There can be more than one ContractImpl for a single

concrete class.

  • ContactImpl has a skip property to ignore specific interface

tests (e.g bar.class).

  • Coverage reporting:

– Unimplemented Tests – Untested Interfaces

  • Maven reporting plugin.
  • Provides a Dynamic interface which triggers testing of the

classes returned from methods.

slide-31
SLIDE 31

More Info

  • https://github.com/Claudenw/junit-contracts
  • Maven:

<dependency> <groupId>org.xenei</groupId> <artifactId>junit-contracts</artifactId> <version>0.1.5</version> </dependency>

  • Simplifying Contract Testing, Dr. Dobb's Journal, May
  • 2014. http://www.drdobbs.com/testing/simplifying-

contract-testing/240167128

slide-32
SLIDE 32

QA