├── lib
├── jpa
│ ├── jta.jar
│ ├── dom4j.jar
│ ├── log4j.jar
│ ├── javassist.jar
│ ├── slf4j-api.jar
│ ├── antlr-2.7.6.jar
│ ├── hibernate-core.jar
│ ├── slf4j-log4j12.jar
│ ├── ejb3-persistence.jar
│ ├── hibernate-annotations.jar
│ ├── commons-collections-3.1.jar
│ ├── hibernate-entitymanager.jar
│ ├── hibernate-commons-annotations.jar
│ └── HIBERNATE-LICENSE
├── javadb
│ ├── derby.jar
│ ├── derbynet.jar
│ ├── derbyrun.jar
│ ├── derbyclient.jar
│ └── derbytools.jar
├── jmock
│ ├── objenesis-1.0.jar
│ ├── cglib-nodep-2.2.jar
│ ├── jmock-2.6-SNAPSHOT.jar
│ ├── jmock-junit4-2.6-SNAPSHOT.jar
│ ├── jmock-legacy-2.6-SNAPSHOT.jar
│ └── JMOCK-LICENSE
├── junit
│ ├── junit-4.6-src.jar
│ └── junit-dep-4.6.jar
├── hamcrest
│ ├── hamcrest-core-1.2.jar
│ ├── hamcrest-library-1.2.jar
│ └── LICENSE
└── apache-commons
│ ├── commons-io-1.4.jar
│ ├── commons-lang-2.4.jar
│ ├── commons-io-1.4-sources.jar
│ └── commons-lang-2.4-sources.jar
├── .idea
├── dictionaries
│ └── nat.xml
├── copyright
│ └── profiles_settings.xml
├── ant.xml
├── encodings.xml
├── vcs.xml
├── libraries
│ ├── jpa.xml
│ ├── jmock.xml
│ ├── junit.xml
│ ├── javadb.xml
│ ├── hamcrest.xml
│ └── apache_commons.xml
├── compiler.xml
├── modules.xml
├── misc.xml
└── uiDesigner.xml
├── common
├── src
│ └── book
│ │ └── example
│ │ └── common
│ │ ├── searching
│ │ ├── Auction.java
│ │ ├── AuctionHouse.java
│ │ ├── async
│ │ │ └── AuctionSearchConsumer.java
│ │ ├── AuctionDescription.java
│ │ └── StubAuctionHouse.java
│ │ └── exceptions
│ │ └── Defect.java
└── common.iml
├── testing-persistence
├── src
│ ├── book
│ │ └── example
│ │ │ └── persistence
│ │ │ ├── tests
│ │ │ ├── builders
│ │ │ │ ├── Builder.java
│ │ │ │ ├── AbstractBuilder.java
│ │ │ │ ├── PayMateDetailsBuilder.java
│ │ │ │ ├── AuthorisationBuilder.java
│ │ │ │ ├── AuctionSiteBuilder.java
│ │ │ │ ├── AuctionSiteLoginBuilder.java
│ │ │ │ ├── AddressBuilder.java
│ │ │ │ ├── CreditCardDetailsBuilder.java
│ │ │ │ └── CustomerBuilder.java
│ │ │ ├── UnitOfWork.java
│ │ │ ├── QueryUnitOfWork.java
│ │ │ ├── JPATransactor.java
│ │ │ ├── DatabaseCleaner.java
│ │ │ ├── PersistenceReflection.java
│ │ │ ├── PersistabilityTest.java
│ │ │ └── PersistentCustomerBaseTest.java
│ │ │ ├── model
│ │ │ ├── CustomerBase.java
│ │ │ ├── PaymentMethod.java
│ │ │ ├── Authorisation.java
│ │ │ ├── PayMateDetails.java
│ │ │ ├── AuctionSite.java
│ │ │ ├── Address.java
│ │ │ ├── AuctionSiteCredentials.java
│ │ │ ├── CreditCardDetails.java
│ │ │ └── Customer.java
│ │ │ └── jpa
│ │ │ └── PersistentCustomerBase.java
│ └── META-INF
│ │ └── persistence.xml
├── README
├── scripts
│ ├── example-db
│ └── example-db.ddl
└── testing-persistence.iml
├── testing-asynchronous-systems
├── src
│ └── book
│ │ └── example
│ │ └── async
│ │ ├── polling
│ │ ├── Probe.java
│ │ ├── FileLengthProbe.java
│ │ └── Poller.java
│ │ ├── Timeout.java
│ │ ├── TimeoutTests.java
│ │ └── notifications
│ │ ├── NotificationTraceTests.java
│ │ └── NotificationTrace.java
└── testing-asynchronous-systems.iml
├── testing-multithreaded-code
├── src
│ └── book
│ │ └── example
│ │ └── threading
│ │ ├── races
│ │ ├── AtomicBigCounter.java
│ │ ├── AtomicBigCounterTests.java
│ │ └── MultithreadedStressTester.java
│ │ └── executor
│ │ ├── DecoratingImposteriser.java
│ │ ├── AuctionSearch_v1.java
│ │ ├── AuctionSearch_v3.java
│ │ ├── AuctionSearch_v2.java
│ │ ├── AuctionSearch_v4.java
│ │ ├── SynchronisingImposteriser.java
│ │ ├── AuctionSearch_v2_Tests.java
│ │ ├── AuctionSearchStressTests.java
│ │ ├── AuctionSearchTests_v3.java
│ │ ├── AuctionSearch_v3_Tests.java
│ │ └── AuctionSearch_v1_Tests.java
└── testing-multithreaded-code.iml
├── diagnostics
├── diagnostics.iml
└── src
│ └── book
│ └── example
│ └── diagnostics
│ └── DiagnosticsExamples.java
├── custom-hamcrest-matcher
├── custom-hamcrest-matcher.iml
└── src
│ └── book
│ └── example
│ └── hamcrest
│ ├── StringStartsWithMatcher.java
│ ├── AbstractMatcherTest.java
│ └── StringStartsWithMatcherTest.java
└── flexibility
├── flexibility.iml
└── src
└── book
└── example
└── flexibility
├── ordering
├── AuctionChannel.java
├── AuctionSearch.java
├── AuctionSearcher.java
├── AuctionChannelTest.java
├── AuctionSearcherTest.java
└── AuctionSearchTest.java
├── neighbours
├── MoreThanImmediateNeighbours2.java
├── MoreThanImmediateNeighbours.java
├── MoreThanImmediateNeighboursTest2.java
├── MoreThanImmediateNeighboursTest.java
└── MoreThanImmediateNeighboursRevisitedTests.java
└── matchers
└── MatchingTest.java
/lib/jpa/jta.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/jta.jar
--------------------------------------------------------------------------------
/lib/jpa/dom4j.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/dom4j.jar
--------------------------------------------------------------------------------
/lib/jpa/log4j.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/log4j.jar
--------------------------------------------------------------------------------
/lib/javadb/derby.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/javadb/derby.jar
--------------------------------------------------------------------------------
/lib/jpa/javassist.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/javassist.jar
--------------------------------------------------------------------------------
/lib/jpa/slf4j-api.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/slf4j-api.jar
--------------------------------------------------------------------------------
/lib/javadb/derbynet.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/javadb/derbynet.jar
--------------------------------------------------------------------------------
/lib/javadb/derbyrun.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/javadb/derbyrun.jar
--------------------------------------------------------------------------------
/lib/jpa/antlr-2.7.6.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/antlr-2.7.6.jar
--------------------------------------------------------------------------------
/lib/javadb/derbyclient.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/javadb/derbyclient.jar
--------------------------------------------------------------------------------
/lib/javadb/derbytools.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/javadb/derbytools.jar
--------------------------------------------------------------------------------
/lib/jpa/hibernate-core.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/hibernate-core.jar
--------------------------------------------------------------------------------
/lib/jpa/slf4j-log4j12.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/slf4j-log4j12.jar
--------------------------------------------------------------------------------
/.idea/dictionaries/nat.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/lib/jmock/objenesis-1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jmock/objenesis-1.0.jar
--------------------------------------------------------------------------------
/lib/jpa/ejb3-persistence.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/ejb3-persistence.jar
--------------------------------------------------------------------------------
/lib/junit/junit-4.6-src.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/junit/junit-4.6-src.jar
--------------------------------------------------------------------------------
/lib/junit/junit-dep-4.6.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/junit/junit-dep-4.6.jar
--------------------------------------------------------------------------------
/lib/jmock/cglib-nodep-2.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jmock/cglib-nodep-2.2.jar
--------------------------------------------------------------------------------
/lib/jmock/jmock-2.6-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jmock/jmock-2.6-SNAPSHOT.jar
--------------------------------------------------------------------------------
/lib/jpa/hibernate-annotations.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/hibernate-annotations.jar
--------------------------------------------------------------------------------
/lib/hamcrest/hamcrest-core-1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/hamcrest/hamcrest-core-1.2.jar
--------------------------------------------------------------------------------
/lib/jpa/commons-collections-3.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/commons-collections-3.1.jar
--------------------------------------------------------------------------------
/lib/jpa/hibernate-entitymanager.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/hibernate-entitymanager.jar
--------------------------------------------------------------------------------
/lib/apache-commons/commons-io-1.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/apache-commons/commons-io-1.4.jar
--------------------------------------------------------------------------------
/lib/hamcrest/hamcrest-library-1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/hamcrest/hamcrest-library-1.2.jar
--------------------------------------------------------------------------------
/lib/apache-commons/commons-lang-2.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/apache-commons/commons-lang-2.4.jar
--------------------------------------------------------------------------------
/lib/jmock/jmock-junit4-2.6-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jmock/jmock-junit4-2.6-SNAPSHOT.jar
--------------------------------------------------------------------------------
/lib/jmock/jmock-legacy-2.6-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jmock/jmock-legacy-2.6-SNAPSHOT.jar
--------------------------------------------------------------------------------
/lib/jpa/hibernate-commons-annotations.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/jpa/hibernate-commons-annotations.jar
--------------------------------------------------------------------------------
/lib/apache-commons/commons-io-1.4-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/apache-commons/commons-io-1.4-sources.jar
--------------------------------------------------------------------------------
/lib/apache-commons/commons-lang-2.4-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npryce/goos-code-examples/HEAD/lib/apache-commons/commons-lang-2.4-sources.jar
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/common/src/book/example/common/searching/Auction.java:
--------------------------------------------------------------------------------
1 | package book.example.common.searching;
2 |
3 | public interface Auction {
4 | // Just a skeleton for this example
5 | }
6 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/Builder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | public interface Builder {
4 | T build();
5 | }
6 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/UnitOfWork.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests;
2 |
3 | public interface UnitOfWork {
4 | void work() throws Exception;
5 | }
6 |
--------------------------------------------------------------------------------
/.idea/ant.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/libraries/jpa.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/common/src/book/example/common/searching/AuctionHouse.java:
--------------------------------------------------------------------------------
1 | package book.example.common.searching;
2 |
3 | import java.util.List;
4 | import java.util.Set;
5 |
6 | public interface AuctionHouse {
7 | List findAuctions(Set keywords);
8 |
9 | Auction joinAuction(String auctionId);
10 | }
11 |
--------------------------------------------------------------------------------
/.idea/libraries/jmock.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/libraries/junit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/libraries/javadb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/libraries/hamcrest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/common/src/book/example/common/exceptions/Defect.java:
--------------------------------------------------------------------------------
1 | package book.example.common.exceptions;
2 |
3 | public class Defect extends RuntimeException {
4 | public Defect(String message) {
5 | super(message);
6 | }
7 |
8 | public Defect(String message, Throwable cause) {
9 | super(message, cause);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/CustomerBase.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import java.util.Date;
4 | import java.util.List;
5 |
6 |
7 | public interface CustomerBase {
8 | void addCustomer(Customer user);
9 |
10 | List customersWithExpiredCreditCardsAsOf(Date deadline);
11 | }
12 |
--------------------------------------------------------------------------------
/.idea/libraries/apache_commons.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/testing-asynchronous-systems/src/book/example/async/polling/Probe.java:
--------------------------------------------------------------------------------
1 | package book.example.async.polling;
2 |
3 | import org.hamcrest.Description;
4 |
5 | public interface Probe {
6 | boolean isSatisfied();
7 |
8 | void sample();
9 |
10 | void describeAcceptanceCriteriaTo(Description d);
11 |
12 | void describeFailureTo(Description d);
13 | }
14 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/QueryUnitOfWork.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests;
2 |
3 | public abstract class QueryUnitOfWork implements UnitOfWork {
4 | public T result;
5 |
6 | public void work() throws Exception {
7 | result = query();
8 | }
9 |
10 | public abstract T query() throws Exception;
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/book/example/common/searching/async/AuctionSearchConsumer.java:
--------------------------------------------------------------------------------
1 | package book.example.common.searching.async;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 |
5 | import java.util.List;
6 |
7 | public interface AuctionSearchConsumer {
8 | void auctionSearchFound(List auctions);
9 |
10 | void auctionSearchFinished();
11 | }
12 |
--------------------------------------------------------------------------------
/testing-persistence/README:
--------------------------------------------------------------------------------
1 | To run the code in this module, first run the following command to create the database:
2 |
3 | testing-persistence/scripts/example-db create
4 |
5 | To delete the database again, run:
6 |
7 | testing-persistence/scripts/example-db drop
8 |
9 | To recreate the database from scratch, deleting all the data in it, run:
10 |
11 | testing-persistence/scripts/example-db recreate
12 |
13 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/AbstractBuilder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | public abstract class AbstractBuilder, B> implements Cloneable, Builder {
4 | @Override
5 | @SuppressWarnings("unchecked")
6 | protected T clone() {
7 | try {
8 | return (T) super.clone();
9 | } catch (CloneNotSupportedException e) {
10 | throw new Error(e);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/races/AtomicBigCounter.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.races;
2 |
3 | import java.math.BigInteger;
4 |
5 | /**
6 | * This class is not properly synchronised, to demonstrate how the {@link MultithreadedStressTester} works.
7 | */
8 | public class AtomicBigCounter {
9 | private BigInteger count = BigInteger.ZERO;
10 |
11 | public BigInteger count() {
12 | return count;
13 | }
14 |
15 | public void inc() {
16 | count = count.add(BigInteger.ONE);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/common/common.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/diagnostics/diagnostics.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/custom-hamcrest-matcher/custom-hamcrest-matcher.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/PaymentMethod.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import javax.persistence.*;
4 |
5 | import static javax.persistence.DiscriminatorType.STRING;
6 | import static javax.persistence.GenerationType.AUTO;
7 | import static javax.persistence.InheritanceType.JOINED;
8 |
9 | @Entity
10 | @Inheritance(strategy = JOINED)
11 | @DiscriminatorColumn(name = "type", discriminatorType = STRING)
12 | public abstract class PaymentMethod {
13 | @Id
14 | @GeneratedValue(strategy = AUTO)
15 | @SuppressWarnings("unused")
16 | private Integer id;
17 |
18 | protected PaymentMethod() {
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/testing-asynchronous-systems/src/book/example/async/Timeout.java:
--------------------------------------------------------------------------------
1 | package book.example.async;
2 |
3 | public class Timeout {
4 | private final long endTime;
5 |
6 | public Timeout(long duration) {
7 | this.endTime = System.currentTimeMillis() + duration;
8 | }
9 |
10 | public boolean hasTimedOut() {
11 | return timeRemaining() <= 0;
12 | }
13 |
14 | public void waitOn(Object lock) throws InterruptedException {
15 | long waitTime = timeRemaining();
16 | if (waitTime > 0) lock.wait(waitTime);
17 | }
18 |
19 | private long timeRemaining() {
20 | return endTime - System.currentTimeMillis();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/Authorisation.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import javax.persistence.Embeddable;
4 |
5 | @Embeddable
6 | public class Authorisation {
7 | private String userName;
8 | private String password;
9 |
10 | public Authorisation(String userName, String password) {
11 | this.userName = userName;
12 | this.password = password;
13 | }
14 |
15 | public String getUserName() {
16 | return userName;
17 | }
18 |
19 | public String getPassword() {
20 | return password;
21 | }
22 |
23 | protected Authorisation() {
24 | // For JPA
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/testing-asynchronous-systems/testing-asynchronous-systems.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/PayMateDetails.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import javax.persistence.Embedded;
4 | import javax.persistence.Entity;
5 |
6 | @Entity
7 | public class PayMateDetails extends PaymentMethod {
8 | @Embedded
9 | private Authorisation authorisation;
10 |
11 | public PayMateDetails(Authorisation authorisation) {
12 | this.authorisation = authorisation;
13 | }
14 |
15 | public Authorisation getAuthorisation() {
16 | return authorisation;
17 | }
18 |
19 | public void setAuthorisation(Authorisation authorisation) {
20 | this.authorisation = authorisation;
21 | }
22 |
23 | public PayMateDetails() {
24 | // For JPA
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/PayMateDetailsBuilder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | import book.example.persistence.model.PayMateDetails;
4 |
5 | public class PayMateDetailsBuilder extends AbstractBuilder {
6 | private AuthorisationBuilder authorisationBuilder = new AuthorisationBuilder();
7 |
8 | public PayMateDetails build() {
9 | return new PayMateDetails(authorisationBuilder.build());
10 | }
11 |
12 | public PayMateDetailsBuilder withAuthorisation(AuthorisationBuilder authorisationBuilder) {
13 | PayMateDetailsBuilder other = clone();
14 | other.authorisationBuilder = authorisationBuilder;
15 | return other;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/testing-multithreaded-code.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/testing-persistence/scripts/example-db:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SAMEDIR=$(dirname "$0")
4 | BASEDIR=$(cd "$SAMEDIR/../.." ; pwd)
5 | DB="$BASEDIR/build/example.db"
6 | DB_URL="jdbc:derby:$DB;create=true"
7 |
8 | function create_db() {
9 | echo "creating $DB"
10 | mkdir -p $(dirname "$DB")
11 | java -Dij.database="$DB_URL" \
12 | -jar $BASEDIR/lib/javadb/derbyrun.jar \
13 | ij "$SAMEDIR/example-db.ddl"
14 | echo
15 | }
16 |
17 | function drop_db() {
18 | echo "removing $DB"
19 | rm -rf "$DB"
20 | }
21 |
22 |
23 | case $1 in
24 | create)
25 | create_db ;;
26 |
27 | drop)
28 | drop_db ;;
29 |
30 | recreate)
31 | drop_db
32 | create_db ;;
33 |
34 | *)
35 | echo "usage: $0 {create|drop|recreate}"
36 | exit 1
37 | ;;
38 | esac
39 |
--------------------------------------------------------------------------------
/testing-persistence/testing-persistence.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/common/src/book/example/common/searching/AuctionDescription.java:
--------------------------------------------------------------------------------
1 | package book.example.common.searching;
2 |
3 | import org.apache.commons.lang.builder.ToStringStyle;
4 |
5 | import static org.apache.commons.lang.builder.ToStringBuilder.reflectionToString;
6 |
7 | public class AuctionDescription {
8 | public final AuctionHouse auctionHouse;
9 | public final String auctionId;
10 | public final String description;
11 | // etc...
12 |
13 | public AuctionDescription(AuctionHouse auctionHouse, String auctionId, String description) {
14 | this.auctionHouse = auctionHouse;
15 | this.auctionId = auctionId;
16 | this.description = description;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/AuthorisationBuilder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | import book.example.persistence.model.Authorisation;
4 |
5 | public class AuthorisationBuilder extends AbstractBuilder {
6 | private String userName = "user";
7 | private String password = "pass";
8 |
9 | public Authorisation build() {
10 | return new Authorisation(userName, password);
11 | }
12 |
13 | AuthorisationBuilder withUserName(String userName) {
14 | AuthorisationBuilder other = clone();
15 | other.userName = userName;
16 | return other;
17 | }
18 |
19 | AuthorisationBuilder withPassword(String password) {
20 | AuthorisationBuilder other = clone();
21 | other.password = password;
22 | return other;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/flexibility/flexibility.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/AuctionSite.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import javax.persistence.Entity;
4 | import javax.persistence.GeneratedValue;
5 | import javax.persistence.Id;
6 |
7 | import static javax.persistence.GenerationType.AUTO;
8 |
9 | @Entity
10 | public class AuctionSite {
11 | private String name;
12 | private String siteURL;
13 |
14 |
15 | public AuctionSite(String name, String siteURL) {
16 | this.name = name;
17 | this.siteURL = siteURL;
18 | }
19 |
20 | public String getName() {
21 | return name;
22 | }
23 |
24 | public String getSiteURL() {
25 | return siteURL;
26 | }
27 |
28 | @Id()
29 | @GeneratedValue(strategy = AUTO)
30 | @SuppressWarnings("unused")
31 | private Integer id;
32 |
33 | protected AuctionSite() {
34 | // For JPA
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/AuctionSiteBuilder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | import book.example.persistence.model.AuctionSite;
4 |
5 | public class AuctionSiteBuilder extends AbstractBuilder {
6 | private String name = "eCove";
7 | private String siteURL = "http://www.ecove.com";
8 |
9 | public AuctionSite build() {
10 | return new AuctionSite(name, siteURL);
11 | }
12 |
13 | public static AuctionSiteBuilder anAuctionSite() {
14 | return new AuctionSiteBuilder();
15 | }
16 |
17 | public AuctionSiteBuilder withName(String aName) {
18 | AuctionSiteBuilder other = this.clone();
19 | other.name = aName;
20 | return other;
21 | }
22 |
23 | public AuctionSiteBuilder withSiteURL(String aSiteURL) {
24 | AuctionSiteBuilder other = this.clone();
25 | other.siteURL = aSiteURL;
26 | return other;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/testing-asynchronous-systems/src/book/example/async/TimeoutTests.java:
--------------------------------------------------------------------------------
1 | package book.example.async;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertTrue;
6 |
7 | public class TimeoutTests {
8 | @Test
9 | public void reportsIfTimedOut() throws InterruptedException {
10 | Timeout timeout = new Timeout(100);
11 | assertTrue("should not have timed out", !timeout.hasTimedOut());
12 | Thread.sleep(100);
13 | assertTrue("should have timed out", timeout.hasTimedOut());
14 | }
15 |
16 | @Test(timeout = 300)
17 | public void waitsForTimeout() throws InterruptedException {
18 | final Object lock = new Object();
19 |
20 | long start = System.currentTimeMillis();
21 | Timeout timeout = new Timeout(250);
22 |
23 | synchronized (lock) {
24 | timeout.waitOn(lock);
25 | }
26 |
27 | long woken = System.currentTimeMillis();
28 |
29 | assertTrue("should have waited until the timeout", (woken - start) >= 250);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/JPATransactor.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests;
2 |
3 | import javax.persistence.EntityManager;
4 | import javax.persistence.EntityTransaction;
5 | import javax.persistence.PersistenceException;
6 |
7 | public class JPATransactor {
8 | private final EntityManager entityManager;
9 |
10 | public JPATransactor(EntityManager entityManager) {
11 | this.entityManager = entityManager;
12 | }
13 |
14 | public void perform(UnitOfWork unitOfWork) throws Exception {
15 | final EntityTransaction transaction = entityManager.getTransaction();
16 | transaction.begin();
17 | try {
18 | unitOfWork.work();
19 | transaction.commit();
20 | } catch (PersistenceException e) {
21 | throw e;
22 | } catch (Exception e) {
23 | transaction.rollback();
24 | throw e;
25 | }
26 | }
27 |
28 | public T performQuery(QueryUnitOfWork query) throws Exception {
29 | perform(query);
30 | return query.result;
31 | }
32 | }
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/ordering/AuctionChannel.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.ordering;
2 |
3 |
4 | public class AuctionChannel {
5 | public interface AuctionConnection {
6 | void send(String message);
7 | }
8 |
9 | public static class AuctionDescription {
10 | }
11 |
12 | ;
13 |
14 | public interface AuctionConnectionFinder {
15 | AuctionConnection findConnectionFor(AuctionDescription description);
16 | }
17 |
18 | private final AuctionConnectionFinder connectionFinder;
19 |
20 | public AuctionChannel(AuctionConnectionFinder connectionFinder) {
21 | this.connectionFinder = connectionFinder;
22 | }
23 |
24 | public void sendMessageTo(String message, Iterable auctionDescriptions) {
25 | for (AuctionDescription auctionDescription : auctionDescriptions) {
26 | final AuctionConnection connection = connectionFinder.findConnectionFor(auctionDescription);
27 | if (connection != null) {
28 | connection.send(message);
29 | return;
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/Address.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import javax.persistence.Entity;
4 | import javax.persistence.GeneratedValue;
5 | import javax.persistence.Id;
6 |
7 | import static javax.persistence.GenerationType.AUTO;
8 |
9 | @Entity
10 | public class Address {
11 | private String street;
12 | private String town;
13 | private String country;
14 | private String postCode;
15 |
16 | public Address(String street, String town, String country, String postCode) {
17 | this.street = street;
18 | this.town = town;
19 | this.country = country;
20 | this.postCode = postCode;
21 | }
22 |
23 | public String getStreet() {
24 | return street;
25 | }
26 |
27 | public String getTown() {
28 | return town;
29 | }
30 |
31 | public String getCountry() {
32 | return country;
33 | }
34 |
35 | public String getPostCode() {
36 | return postCode;
37 | }
38 |
39 | // JPA stuff
40 | protected Address() {
41 | }
42 |
43 | @Id
44 | @GeneratedValue(strategy = AUTO)
45 | @SuppressWarnings("unused")
46 | private int id;
47 | }
48 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/AuctionSiteCredentials.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import javax.persistence.*;
4 |
5 | import static javax.persistence.GenerationType.AUTO;
6 |
7 | @Entity
8 | public class AuctionSiteCredentials {
9 | @ManyToOne
10 | private AuctionSite auctionSite;
11 |
12 | @Embedded
13 | private Authorisation auth;
14 |
15 | public AuctionSiteCredentials(AuctionSite site, Authorisation auth) {
16 | this.auctionSite = site;
17 | this.auth = auth;
18 | }
19 |
20 | public AuctionSite getSite() {
21 | return auctionSite;
22 | }
23 |
24 | public Authorisation getAuth() {
25 | return auth;
26 | }
27 |
28 | /**
29 | * Would really have an API like:
30 | *
31 | * AuctionSiteSession login() throws AuthorisationException {
32 | * return site.login(auth);
33 | * }
34 | *
35 | * but we don't have an Auction interface yet
36 | */
37 |
38 | @Id
39 | @GeneratedValue(strategy = AUTO)
40 | @SuppressWarnings("unused")
41 | private int id;
42 |
43 | protected AuctionSiteCredentials() {
44 | // For JPA
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/jpa/PersistentCustomerBase.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.jpa;
2 |
3 | import book.example.persistence.model.Customer;
4 | import book.example.persistence.model.CustomerBase;
5 |
6 | import javax.persistence.EntityManager;
7 | import javax.persistence.Query;
8 | import java.util.Date;
9 | import java.util.List;
10 |
11 | public class PersistentCustomerBase implements CustomerBase {
12 | private final EntityManager entityManager;
13 |
14 | public PersistentCustomerBase(EntityManager entityManager) {
15 | this.entityManager = entityManager;
16 | }
17 |
18 | public void addCustomer(Customer customer) {
19 | entityManager.persist(customer);
20 | }
21 |
22 | @SuppressWarnings("unchecked")
23 | public List customersWithExpiredCreditCardsAsOf(Date deadline) {
24 | Query query = entityManager.createQuery(
25 | "select c from Customer c, CreditCardDetails d " +
26 | "where d member of c.paymentMethods " +
27 | " and d.expiryDate < :deadline");
28 | query.setParameter("deadline", deadline);
29 | return query.getResultList();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/ordering/AuctionSearch.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.ordering;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.async.AuctionSearchConsumer;
6 |
7 | import java.util.List;
8 | import java.util.Set;
9 |
10 | public class AuctionSearch {
11 | private final List extends AuctionHouse> auctionHouses;
12 | private final AuctionSearchConsumer consumer;
13 |
14 | public AuctionSearch(List extends AuctionHouse> auctionHouses, AuctionSearchConsumer consumer) {
15 | this.auctionHouses = auctionHouses;
16 | this.consumer = consumer;
17 | }
18 |
19 | public void search(Set keywords) {
20 | for (AuctionHouse auctionHouse : auctionHouses) {
21 | search(auctionHouse, keywords);
22 | }
23 | consumer.auctionSearchFinished();
24 | }
25 |
26 | private void search(AuctionHouse auctionHouse, Set keywords) {
27 | List found = auctionHouse.findAuctions(keywords);
28 | if (!found.isEmpty()) {
29 | consumer.auctionSearchFound(found);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/testing-asynchronous-systems/src/book/example/async/polling/FileLengthProbe.java:
--------------------------------------------------------------------------------
1 | package book.example.async.polling;
2 |
3 | import org.hamcrest.Description;
4 | import org.hamcrest.Matcher;
5 |
6 | import java.io.File;
7 |
8 | public class FileLengthProbe {
9 |
10 | private static final int NOT_SET = -1;
11 |
12 | public static Probe fileLength(String path, final Matcher matcher) {
13 | final File file = new File(path);
14 | return new Probe() {
15 | private long lastFileLength = NOT_SET;
16 |
17 | public void sample() {
18 | lastFileLength = file.length();
19 | }
20 |
21 | public boolean isSatisfied() {
22 | return lastFileLength != NOT_SET && matcher.matches(lastFileLength);
23 | }
24 |
25 | public void describeAcceptanceCriteriaTo(Description d) {
26 | d.appendText(file.getAbsolutePath())
27 | .appendText(" has length ")
28 | .appendDescriptionOf(matcher);
29 | }
30 |
31 | public void describeFailureTo(Description d) {
32 | d.appendText("length was ").appendValue(lastFileLength);
33 | }
34 |
35 | };
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/AuctionSiteLoginBuilder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | import book.example.persistence.model.AuctionSite;
4 | import book.example.persistence.model.AuctionSiteCredentials;
5 | import book.example.persistence.model.Authorisation;
6 |
7 | public class AuctionSiteLoginBuilder extends AbstractBuilder {
8 | private Builder auctionSiteBuilder = new AuctionSiteBuilder();
9 | private Builder authorisationBuilder = new AuthorisationBuilder();
10 |
11 | public AuctionSiteCredentials build() {
12 | return new AuctionSiteCredentials(auctionSiteBuilder.build(), authorisationBuilder.build());
13 | }
14 |
15 | public AuctionSiteLoginBuilder forSite(Builder auctionSiteBuilder) {
16 | AuctionSiteLoginBuilder other = this.clone();
17 | other.auctionSiteBuilder = auctionSiteBuilder;
18 | return other;
19 | }
20 |
21 | public AuctionSiteLoginBuilder with(AuthorisationBuilder authorisationBuilder) {
22 | AuctionSiteLoginBuilder other = this.clone();
23 | other.authorisationBuilder = authorisationBuilder;
24 | return other;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/DecoratingImposteriser.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import org.jmock.api.Imposteriser;
4 | import org.jmock.api.Invocation;
5 | import org.jmock.api.Invokable;
6 |
7 |
8 | public abstract class DecoratingImposteriser implements Imposteriser {
9 | private final Imposteriser imposteriser;
10 |
11 | protected DecoratingImposteriser(Imposteriser imposteriser) {
12 | this.imposteriser = imposteriser;
13 | }
14 |
15 | public boolean canImposterise(Class> type) {
16 | return imposteriser.canImposterise(type);
17 | }
18 |
19 | public T imposterise(Invokable mockObject, Class mockedType, Class>... ancilliaryTypes) {
20 | return imposteriser.imposterise(decorate(mockObject), mockedType, ancilliaryTypes);
21 | }
22 |
23 | private Invokable decorate(final Invokable mockObject) {
24 | return new Invokable() {
25 | public Object invoke(Invocation invocation) throws Throwable {
26 | return applyInvocation(mockObject, invocation);
27 | }
28 | };
29 | }
30 |
31 | protected abstract Object applyInvocation(Invokable imposter, Invocation invocation)
32 | throws Throwable;
33 | }
34 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/custom-hamcrest-matcher/src/book/example/hamcrest/StringStartsWithMatcher.java:
--------------------------------------------------------------------------------
1 | package book.example.hamcrest;
2 |
3 | import org.hamcrest.Description;
4 | import org.hamcrest.Matcher;
5 | import org.hamcrest.TypeSafeMatcher;
6 |
7 | public class StringStartsWithMatcher extends TypeSafeMatcher {
8 | private final String expectedPrefix;
9 |
10 | public StringStartsWithMatcher(String expectedPrefix) {
11 | this.expectedPrefix = expectedPrefix;
12 | }
13 |
14 | @Override
15 | protected boolean matchesSafely(String actual) {
16 | return actual.startsWith(expectedPrefix);
17 | }
18 |
19 | public void describeTo(Description matchDescription) {
20 | matchDescription.appendText("a string starting with ")
21 | .appendValue(expectedPrefix);
22 | }
23 |
24 | @Override
25 | protected void describeMismatchSafely(String actual, Description mismatchDescription) {
26 | String actualPrefix = actual.substring(0, Math.min(actual.length(), expectedPrefix.length()));
27 | mismatchDescription.appendText("started with ")
28 | .appendValue(actualPrefix);
29 | }
30 |
31 | public static Matcher startsWith(String prefix) {
32 | return new StringStartsWithMatcher(prefix);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/AddressBuilder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | import book.example.persistence.model.Address;
4 |
5 | public class AddressBuilder extends AbstractBuilder {
6 | private String street = "1 High Street";
7 | private String town = "Bognor Regis";
8 | private String country = "UK";
9 | private String postCode = "BG1 2FO";
10 |
11 | public AddressBuilder withStreet(String street) {
12 | AddressBuilder other = this.clone();
13 | other.street = street;
14 | return other;
15 | }
16 |
17 | public AddressBuilder withTown(String town) {
18 | AddressBuilder other = this.clone();
19 | other.town = town;
20 | return other;
21 | }
22 |
23 | public AddressBuilder withCountry(String country) {
24 | AddressBuilder other = this.clone();
25 | other.country = country;
26 | return other;
27 | }
28 |
29 | public AddressBuilder withPostCode(String postCode) {
30 | AddressBuilder other = this.clone();
31 | other.postCode = postCode;
32 | return other;
33 | }
34 |
35 | public Address build() {
36 | return new Address(street, town, country, postCode);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/diagnostics/src/book/example/diagnostics/DiagnosticsExamples.java:
--------------------------------------------------------------------------------
1 | package book.example.diagnostics;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.Date;
6 |
7 | import static org.hamcrest.Matchers.equalTo;
8 | import static org.junit.Assert.assertNotNull;
9 | import static org.junit.Assert.assertThat;
10 |
11 | // These are meant to fail!
12 | public class DiagnosticsExamples {
13 | @Test
14 | public void bug1432() {
15 | assertNotNull(null);
16 | }
17 |
18 | @Test
19 | public void exampleWithoutMessage() {
20 | assertThat("Xyzzy", equalTo("Foo"));
21 | }
22 |
23 | @Test
24 | public void exampleWithMessage() {
25 | assertThat("customer's first name", "Xyzzy", equalTo("Foo"));
26 | }
27 |
28 | @Test
29 | public void exampleDates() {
30 | assertThat("payment date", new Date(2000), equalTo(new Date(1000)));
31 | }
32 |
33 | @Test
34 | public void exampleSelfDescribingDates() {
35 | assertThat("payment date", namedDate(2000, "endDate"), equalTo(namedDate(1000, "startDate")));
36 | }
37 |
38 | Date namedDate(long timeValue, final String name) {
39 | return new Date(timeValue) {
40 | public String toString() {
41 | return name;
42 | }
43 | };
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/ordering/AuctionSearcher.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.ordering;
2 |
3 | import java.util.Collection;
4 | import java.util.Set;
5 |
6 | public class AuctionSearcher {
7 |
8 | public interface Auction {
9 | boolean matches(String keyword);
10 | }
11 |
12 | public interface AuctionSearchListener {
13 | void searchMatched(Auction auction);
14 |
15 | void searchFinished();
16 | }
17 |
18 | private final AuctionSearchListener searchListener;
19 | private final Collection auctions;
20 |
21 | public AuctionSearcher(AuctionSearchListener searchListener, Collection auctions) {
22 | this.searchListener = searchListener;
23 | this.auctions = auctions;
24 | }
25 |
26 | public void searchFor(Set keywords) {
27 | for (Auction auction : auctions) {
28 | announceIfAuctionMatches(auction, keywords);
29 | }
30 | searchListener.searchFinished();
31 | }
32 |
33 | private void announceIfAuctionMatches(Auction auction, Set keywords) {
34 | for (String keyword : keywords) {
35 | if (auction.matches(keyword)) {
36 | searchListener.searchMatched(auction);
37 | return;
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/neighbours/MoreThanImmediateNeighbours2.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.neighbours;
2 |
3 | import book.example.flexibility.neighbours.MoreThanImmediateNeighbours.*;
4 |
5 | import java.util.Iterator;
6 |
7 | public class MoreThanImmediateNeighbours2 {
8 | private final Connections connections;
9 |
10 | public MoreThanImmediateNeighbours2(Connections connections) {
11 | this.connections = connections;
12 | }
13 |
14 | ///BEGIN extract-method-for-ticket-manager
15 | public void allUnresolvedIssues(IssueHandler handler) throws Failure {
16 | TicketManager ticketManager = connections.getTicketManager();
17 |
18 | ticketManager.lock();
19 | try {
20 | retrieveUnresolvedIssues(ticketManager.getIssueManager(), handler);
21 | } finally {
22 | ticketManager.unlock();
23 | }
24 | }
25 |
26 | private void retrieveUnresolvedIssues(IssueManager issueManager, IssueHandler handler) {
27 | Iterator issues = issueManager.allIssuesIterator();
28 |
29 | while (issues.hasNext()) {
30 | Issue issue = issues.next();
31 |
32 | if (issue.isUnresolved()) {
33 | handler.accept(issue);
34 | }
35 | }
36 | }
37 | ///END extract-method-for-ticket-manager
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/CreditCardDetails.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import javax.persistence.Entity;
4 | import javax.persistence.ManyToOne;
5 | import java.util.Date;
6 |
7 | import static javax.persistence.CascadeType.PERSIST;
8 | import static javax.persistence.FetchType.EAGER;
9 |
10 | @Entity
11 | public class CreditCardDetails extends PaymentMethod {
12 | private String cardNumber;
13 | private String nameOnCard;
14 | private Date expiryDate;
15 |
16 | @ManyToOne(cascade = PERSIST, fetch = EAGER, optional = false)
17 | private Address billingAddress;
18 |
19 | public CreditCardDetails(String cardNumber, String nameOnCard, Date expiryDate, Address billingAddress) {
20 | this.cardNumber = cardNumber;
21 | this.nameOnCard = nameOnCard;
22 | this.expiryDate = expiryDate;
23 | this.billingAddress = billingAddress;
24 | }
25 |
26 | public Date getExpiryDate() {
27 | return expiryDate;
28 | }
29 |
30 | public String getCardNumber() {
31 | return cardNumber;
32 | }
33 |
34 | public String getNameOnCard() {
35 | return nameOnCard;
36 | }
37 |
38 | public Address getBillingAddress() {
39 | return billingAddress;
40 | }
41 |
42 | protected CreditCardDetails() {
43 | // for JPA
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/common/src/book/example/common/searching/StubAuctionHouse.java:
--------------------------------------------------------------------------------
1 | package book.example.common.searching;
2 |
3 | import java.util.HashMap;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.Set;
7 |
8 | import static java.util.Collections.emptyList;
9 |
10 |
11 | public class StubAuctionHouse implements AuctionHouse {
12 | private final Map, List> searchResults = new HashMap, List>();
13 | private final String name;
14 |
15 | public StubAuctionHouse() {
16 | this.name = getClass().getSimpleName();
17 | }
18 |
19 | public StubAuctionHouse(String name) {
20 | this.name = name;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return name;
26 | }
27 |
28 | public void willReturnSearchResults(Set keywords, List results) {
29 | searchResults.put(keywords, results);
30 | }
31 |
32 | public List findAuctions(Set keywords) {
33 | if (searchResults.containsKey(keywords)) {
34 | return searchResults.get(keywords);
35 | } else {
36 | return emptyList();
37 | }
38 | }
39 |
40 | public Auction joinAuction(String auctionId) {
41 | throw new UnsupportedOperationException("not implemented");
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/DatabaseCleaner.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests;
2 |
3 | import book.example.persistence.model.*;
4 |
5 | import javax.persistence.EntityManager;
6 | import javax.persistence.EntityTransaction;
7 |
8 | public class DatabaseCleaner {
9 | private static final Class>[] ENTITY_TYPES = {
10 | Customer.class,
11 | PaymentMethod.class,
12 | AuctionSiteCredentials.class,
13 | AuctionSite.class,
14 | Address.class
15 | };
16 |
17 | private final EntityManager entityManager;
18 |
19 | public DatabaseCleaner(EntityManager entityManager) {
20 | this.entityManager = entityManager;
21 | }
22 |
23 | public void clean() {
24 | EntityTransaction transaction = entityManager.getTransaction();
25 | transaction.begin();
26 |
27 | for (Class> entityType : ENTITY_TYPES) {
28 | deleteEntities(entityType);
29 | }
30 |
31 | transaction.commit();
32 | }
33 |
34 | private void deleteEntities(Class> entityType) {
35 | entityManager
36 | .createQuery("delete from " + entityNameOf(entityType))
37 | .executeUpdate();
38 | }
39 |
40 | private String entityNameOf(Class> entityType) {
41 | return entityType.getSimpleName();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/hamcrest/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2000-2010, The Hamcrest Team
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5 |
6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8 | * The names of its contributors may be not used to endorse or promote products derived from this software without specific prior written permission.
9 |
10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/races/AtomicBigCounterTests.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.races;
2 |
3 | import org.junit.Test;
4 |
5 | import java.math.BigInteger;
6 |
7 | import static org.hamcrest.Matchers.equalTo;
8 | import static org.junit.Assert.assertThat;
9 |
10 | public class AtomicBigCounterTests {
11 | AtomicBigCounter counter = new AtomicBigCounter();
12 |
13 | @Test
14 | public void
15 | isInitiallyZero() {
16 | assertThat(counter.count(), equalTo(BigInteger.ZERO));
17 | }
18 |
19 | @Test
20 | public void
21 | canIncreaseCounter() {
22 | counter.inc();
23 | assertThat(counter.count(), equalTo(BigInteger.valueOf(1)));
24 |
25 | counter.inc();
26 | assertThat(counter.count(), equalTo(BigInteger.valueOf(2)));
27 |
28 | counter.inc();
29 | assertThat(counter.count(), equalTo(BigInteger.valueOf(3)));
30 | }
31 |
32 | @Test
33 | public void
34 | canIncrementCounterFromMultipleThreadsSimultaneously() throws InterruptedException {
35 | MultithreadedStressTester stressTester = new MultithreadedStressTester(25000);
36 |
37 | stressTester.stress(new Runnable() {
38 | public void run() {
39 | counter.inc();
40 | }
41 | });
42 |
43 | stressTester.shutdown();
44 |
45 | assertThat("final count", counter.count(), equalTo(BigInteger.valueOf(stressTester.totalActionCount())));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/testing-persistence/src/META-INF/persistence.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | org.hibernate.ejb.HibernatePersistence
10 | book.example.persistence.model.Customer
11 | book.example.persistence.model.Address
12 | book.example.persistence.model.PaymentMethod
13 | book.example.persistence.model.CreditCardDetails
14 | book.example.persistence.model.PayMateDetails
15 | book.example.persistence.model.AuctionSite
16 | book.example.persistence.model.AuctionSiteCredentials
17 |
18 |
19 |
21 |
23 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/jmock/JMOCK-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2000-2010, jMock.org
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are
6 | met:
7 |
8 | Redistributions of source code must retain the above copyright notice,
9 | this list of conditions and the following disclaimer. Redistributions
10 | in binary form must reproduce the above copyright notice, this list of
11 | conditions and the following disclaimer in the documentation and/or
12 | other materials provided with the distribution.
13 |
14 | Neither the name of jMock nor the names of its contributors may be
15 | used to endorse or promote products derived from this software without
16 | specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/PersistenceReflection.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests;
2 |
3 | import javax.persistence.Id;
4 | import javax.persistence.Transient;
5 | import java.lang.reflect.Field;
6 |
7 | import static java.lang.reflect.Modifier.isTransient;
8 | import static org.junit.Assert.assertEquals;
9 |
10 | public class PersistenceReflection {
11 | public static Object idOf(Object entity) {
12 | for (Class> c = entity.getClass(); c != Object.class; c = c.getSuperclass()) {
13 | for (Field field : c.getDeclaredFields()) {
14 | if (field.isAnnotationPresent(Id.class)) {
15 | return fieldValue(entity, field);
16 | }
17 | }
18 | }
19 |
20 | throw new IllegalArgumentException(entity + " does not have an entity id");
21 | }
22 |
23 | public static void assertHaveSamePersistentFields(Object e1, Object e2) {
24 | for (Class> c = e1.getClass(); c != Object.class; c = c.getSuperclass()) {
25 | for (Field field : c.getDeclaredFields()) {
26 | if (!isTransient(field.getModifiers()) && !field.isAnnotationPresent(Transient.class)) {
27 | assertEquals(c.getSimpleName() + "." + field.getName(), fieldValue(e1, field), fieldValue(e2, field));
28 | }
29 | }
30 | }
31 | }
32 |
33 | private static Object fieldValue(Object entity, Field field) throws Error {
34 | field.setAccessible(true);
35 | try {
36 | return field.get(entity);
37 | } catch (IllegalAccessException e) {
38 | throw new Error("could not access accessible field " + field);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/CreditCardDetailsBuilder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | import book.example.persistence.model.CreditCardDetails;
4 |
5 | import java.util.Date;
6 |
7 | public class CreditCardDetailsBuilder extends AbstractBuilder {
8 | private String nameOnCard = "bob";
9 | private String cardNumber = "1234567890";
10 | private Date expiryDate = new Date();
11 | private AddressBuilder billingAddressBuilder = new AddressBuilder();
12 |
13 | public CreditCardDetails build() {
14 | return new CreditCardDetails(nameOnCard, cardNumber, expiryDate, billingAddressBuilder.build());
15 | }
16 |
17 | public CreditCardDetailsBuilder withNameOnCard(String nameOnCard) {
18 | CreditCardDetailsBuilder other = clone();
19 | other.nameOnCard = nameOnCard;
20 | return other;
21 | }
22 |
23 | public CreditCardDetailsBuilder withCardNumber(String cardNumber) {
24 | CreditCardDetailsBuilder other = clone();
25 | other.cardNumber = cardNumber;
26 | return other;
27 | }
28 |
29 | public CreditCardDetailsBuilder withExpiryDate(Date expiryDate) {
30 | CreditCardDetailsBuilder other = clone();
31 | other.expiryDate = expiryDate;
32 | return other;
33 | }
34 |
35 | public CreditCardDetailsBuilder withBillingAddress(AddressBuilder billingAddressBuilder) {
36 | CreditCardDetailsBuilder other = clone();
37 | other.billingAddressBuilder = billingAddressBuilder;
38 | return other;
39 | }
40 |
41 | public static CreditCardDetailsBuilder aCreditCard() {
42 | return new CreditCardDetailsBuilder();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/model/Customer.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.model;
2 |
3 | import javax.persistence.*;
4 | import java.util.Set;
5 |
6 | import static javax.persistence.CascadeType.ALL;
7 | import static javax.persistence.GenerationType.AUTO;
8 |
9 | @Entity
10 | public class Customer {
11 | private String name;
12 |
13 | private String email;
14 |
15 | @OneToOne(cascade = ALL)
16 | private Address address;
17 |
18 | @ManyToMany(cascade = ALL)
19 | private Set paymentMethods;
20 |
21 | @ManyToMany(cascade = ALL)
22 | private Set auctionSiteLogins;
23 |
24 | public Customer(String name, String email, Address address, Set paymentMethods, Set auctionSitesUsed) {
25 | this.name = name;
26 | this.email = email;
27 | this.address = address;
28 | this.paymentMethods = paymentMethods;
29 | this.auctionSiteLogins = auctionSitesUsed;
30 | }
31 |
32 | public String name() {
33 | return name;
34 | }
35 |
36 | public String getEmail() {
37 | return email;
38 | }
39 |
40 | public Address getAddress() {
41 | return address;
42 | }
43 |
44 | public Set getPaymentMethods() {
45 | return paymentMethods;
46 | }
47 |
48 | public Set getAuctionSitesUsed() {
49 | return auctionSiteLogins;
50 | }
51 |
52 | public String toString() {
53 | return getClass().getSimpleName() + "[name=" + name + "]";
54 | }
55 |
56 | @Id
57 | @GeneratedValue(strategy = AUTO)
58 | @SuppressWarnings("unused")
59 | private Integer id;
60 |
61 | protected Customer() {
62 | // for JPA
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/testing-asynchronous-systems/src/book/example/async/polling/Poller.java:
--------------------------------------------------------------------------------
1 | package book.example.async.polling;
2 |
3 | import book.example.async.Timeout;
4 | import org.hamcrest.StringDescription;
5 |
6 | public class Poller {
7 | private long timeoutMillis;
8 | private long pollDelayMillis;
9 |
10 | public Poller(long timeoutMillis, long pollDelayMillis) {
11 | this.timeoutMillis = timeoutMillis;
12 | this.pollDelayMillis = pollDelayMillis;
13 | }
14 |
15 | public long getTimeout() {
16 | return timeoutMillis;
17 | }
18 |
19 | public void setTimeout(long timeoutMillis) {
20 | this.timeoutMillis = timeoutMillis;
21 | }
22 |
23 | public long getPollDelay() {
24 | return pollDelayMillis;
25 | }
26 |
27 | public void setPollDelay(long pollDelayMillis) {
28 | this.pollDelayMillis = pollDelayMillis;
29 | }
30 |
31 | public void check(Probe probe) throws InterruptedException {
32 | Timeout timeout = new Timeout(timeoutMillis);
33 |
34 | while (!probe.isSatisfied()) {
35 | if (timeout.hasTimedOut()) {
36 | throw new AssertionError(describeFailureOf(probe));
37 | }
38 | Thread.sleep(pollDelayMillis);
39 |
40 | probe.sample();
41 | }
42 | }
43 |
44 | protected String describeFailureOf(Probe probe) {
45 | StringDescription description = new StringDescription();
46 |
47 | description.appendText("\nTried to look for:\n ");
48 | probe.describeAcceptanceCriteriaTo(description);
49 | description.appendText("\nbut:\n ");
50 | probe.describeFailureTo(description);
51 |
52 | return description.toString();
53 | }
54 |
55 | public static void assertEventually(Probe probe) throws InterruptedException {
56 | new Poller(1000L, 100L).check(probe);
57 | }
58 | }
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/neighbours/MoreThanImmediateNeighbours.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.neighbours;
2 |
3 | import book.example.flexibility.neighbours.MoreThanImmediateNeighboursRevisitedTests.IssueQuery;
4 |
5 | import java.util.Iterator;
6 |
7 | public class MoreThanImmediateNeighbours {
8 | private final Connections connections;
9 |
10 | public MoreThanImmediateNeighbours(Connections connections) {
11 | this.connections = connections;
12 | }
13 |
14 | public void allUnresolvedIssues(IssueHandler handler) throws Failure {
15 | TicketManager ticketManager = connections.getTicketManager();
16 |
17 | ticketManager.lock();
18 | try {
19 | IssueManager issueManager = ticketManager.getIssueManager();
20 | Iterator issues = issueManager.allIssuesIterator();
21 |
22 | while (issues.hasNext()) {
23 | Issue issue = issues.next();
24 |
25 | if (issue.isUnresolved()) {
26 | handler.accept(issue);
27 | }
28 | }
29 | } finally {
30 | ticketManager.unlock();
31 | }
32 | }
33 |
34 | public interface Issue {
35 | boolean isUnresolved();
36 | }
37 |
38 | public interface IssueHandler {
39 | void accept(Issue issue);
40 | }
41 |
42 | public interface Connections {
43 | TicketManager getTicketManager();
44 |
45 | void queryIssueManager(IssueQuery unresolved, IssueHandler handler) throws Failure;
46 | }
47 |
48 | public interface TicketManager {
49 | void lock();
50 |
51 | void unlock();
52 |
53 | IssueManager getIssueManager() throws Failure;
54 | }
55 |
56 | public interface IssueManager {
57 | Iterator allIssuesIterator();
58 | }
59 |
60 | public static class Failure extends Exception {
61 | }
62 |
63 | ;
64 | }
65 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearch_v1.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.async.AuctionSearchConsumer;
6 |
7 | import java.util.List;
8 | import java.util.Set;
9 | import java.util.concurrent.atomic.AtomicInteger;
10 |
11 | public class AuctionSearch_v1 {
12 | private final List auctionHouses;
13 | private final AuctionSearchConsumer consumer;
14 | private final AtomicInteger runningSearchCount = new AtomicInteger();
15 |
16 | public AuctionSearch_v1(List auctionHouses, AuctionSearchConsumer consumer) {
17 | this.auctionHouses = auctionHouses;
18 | this.consumer = consumer;
19 | }
20 |
21 | public void search(Set keywords) {
22 | //BUG2: THIS IS CORRECT
23 | runningSearchCount.set(auctionHouses.size());
24 |
25 | for (AuctionHouse auctionHouse : auctionHouses) {
26 | startSearching(auctionHouse, keywords);
27 | }
28 | }
29 |
30 | private void startSearching(final AuctionHouse auctionHouse, final Set keywords) {
31 | //BUG2: THIS IS INCORRECT
32 | //searchCount.incrementAndGet();
33 |
34 | Thread searchThread = new Thread(new Runnable() {
35 | public void run() {
36 | search(auctionHouse, keywords);
37 | }
38 | });
39 | searchThread.start();
40 | }
41 |
42 | private void search(AuctionHouse auctionHouse, Set keywords) {
43 | List found = auctionHouse.findAuctions(keywords);
44 |
45 | //BUG1: THIS IS CORRECT
46 | if (!found.isEmpty()) {
47 | consumer.auctionSearchFound(found);
48 | }
49 |
50 | //BUG1: THIS IS INCORRECT
51 | //consumer.auctionSearchFound(found);
52 |
53 | if (runningSearchCount.decrementAndGet() == 0) {
54 | consumer.auctionSearchFinished();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/custom-hamcrest-matcher/src/book/example/hamcrest/AbstractMatcherTest.java:
--------------------------------------------------------------------------------
1 | package book.example.hamcrest;
2 |
3 | import org.hamcrest.Description;
4 | import org.hamcrest.Matcher;
5 | import org.hamcrest.StringDescription;
6 | import org.junit.Test;
7 |
8 | import static org.junit.Assert.*;
9 |
10 | public abstract class AbstractMatcherTest {
11 | /**
12 | * Create an instance of the Matcher so some generic safety-net tests can be run on it.
13 | */
14 | protected abstract Matcher> createMatcher();
15 |
16 | protected static final Object ARGUMENT_IGNORED = new Object();
17 | protected static final Object ANY_NON_NULL_ARGUMENT = new Object();
18 |
19 | public static void assertMatches(String message, Matcher super T> c, T arg) {
20 | assertTrue(message, c.matches(arg));
21 | }
22 |
23 | public static void assertDoesNotMatch(String message, Matcher super T> c, T arg) {
24 | assertFalse(message, c.matches(arg));
25 | }
26 |
27 | public static void assertDescription(String expected, Matcher> matcher) {
28 | Description description = new StringDescription();
29 | description.appendDescriptionOf(matcher);
30 | assertEquals("Expected description", expected, description.toString());
31 | }
32 |
33 | public static void assertMismatchDescription(String expected, Matcher super T> matcher, T arg) {
34 | Description description = new StringDescription();
35 | assertFalse("Precondtion: Matcher should not match item.", matcher.matches(arg));
36 | matcher.describeMismatch(arg, description);
37 | assertEquals("Expected mismatch description", expected, description.toString());
38 | }
39 |
40 | @Test
41 | public void isNullSafe() {
42 | // should not throw a NullPointerException
43 | createMatcher().matches(null);
44 | }
45 |
46 | @Test
47 | public void copesWithUnknownTypes() {
48 | // should not throw ClassCastException
49 | createMatcher().matches(new UnknownType());
50 | }
51 |
52 | public static class UnknownType {
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearch_v3.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.async.AuctionSearchConsumer;
6 |
7 | import java.util.List;
8 | import java.util.Set;
9 | import java.util.concurrent.Executor;
10 | import java.util.concurrent.atomic.AtomicInteger;
11 |
12 | /**
13 | * The functionality is done, but the synchronisation is incomplete.
14 | */
15 | public class AuctionSearch_v3 {
16 | private final Executor executor;
17 | private final List auctionHouses;
18 | private final AuctionSearchConsumer consumer;
19 | private final AtomicInteger runningSearchCount = new AtomicInteger();
20 |
21 | public AuctionSearch_v3(Executor executor, List auctionHouses, AuctionSearchConsumer consumer) {
22 | this.executor = executor;
23 | this.auctionHouses = auctionHouses;
24 | this.consumer = consumer;
25 | }
26 |
27 | public void search(Set keywords) {
28 | for (AuctionHouse auctionHouse : auctionHouses) {
29 | startSearching(auctionHouse, keywords);
30 | }
31 | }
32 |
33 | private void startSearching(final AuctionHouse auctionHouse, final Set keywords) {
34 | runningSearchCount.incrementAndGet();
35 |
36 | executor.execute(new Runnable() {
37 | public void run() {
38 | search(auctionHouse, keywords);
39 | }
40 | });
41 | }
42 |
43 | private void search(AuctionHouse auctionHouse, Set keywords) {
44 | // BUG1: THIS IS CORRECT
45 | List found = auctionHouse.findAuctions(keywords);
46 | if (!found.isEmpty()) {
47 | consumer.auctionSearchFound(found);
48 | }
49 |
50 | // BUG1: THIS IS INCORRECT
51 | //consumer.auctionSearchFound(auctionHouse.findAuctions(keywords));
52 |
53 | if (runningSearchCount.decrementAndGet() == 0) {
54 | consumer.auctionSearchFinished();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearch_v2.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.async.AuctionSearchConsumer;
6 |
7 | import java.util.List;
8 | import java.util.Set;
9 | import java.util.concurrent.Executor;
10 |
11 | /**
12 | * No synchronisation yet... let's get the functionality sorted
13 | */
14 | public class AuctionSearch_v2 {
15 | private final Executor executor;
16 | private final List auctionHouses;
17 | private final AuctionSearchConsumer consumer;
18 |
19 | private int runningSearchCount = 0;
20 |
21 | public AuctionSearch_v2(Executor executor,
22 | List auctionHouses,
23 | AuctionSearchConsumer consumer) {
24 | this.executor = executor;
25 | this.auctionHouses = auctionHouses;
26 | this.consumer = consumer;
27 | }
28 |
29 | public void search(Set keywords) {
30 | for (AuctionHouse auctionHouse : auctionHouses) {
31 | startSearching(auctionHouse, keywords);
32 | }
33 | }
34 |
35 | private void startSearching(final AuctionHouse auctionHouse,
36 | final Set keywords) {
37 | runningSearchCount++;
38 |
39 | executor.execute(new Runnable() {
40 | public void run() {
41 | search(auctionHouse, keywords);
42 | }
43 | });
44 | }
45 |
46 | private void search(AuctionHouse auctionHouse, Set keywords) {
47 | // BUG1: THIS IS CORRECT
48 | List found = auctionHouse.findAuctions(keywords);
49 | if (!found.isEmpty()) {
50 | consumer.auctionSearchFound(found);
51 | }
52 |
53 | // BUG1: THIS IS INCORRECT
54 | //consumer.auctionSearchFound(auctionHouse.findAuctions(keywords));
55 |
56 | runningSearchCount--;
57 | if (runningSearchCount == 0) {
58 | consumer.auctionSearchFinished();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearch_v4.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.async.AuctionSearchConsumer;
6 |
7 | import java.util.List;
8 | import java.util.Set;
9 | import java.util.concurrent.Executor;
10 | import java.util.concurrent.atomic.AtomicInteger;
11 |
12 | /**
13 | * This fixes the synchronisation error that is detected by the {@link AuctionSearchStressTests}
14 | */
15 | public class AuctionSearch_v4 {
16 | private final Executor executor;
17 | private final List auctionHouses;
18 | private final AuctionSearchConsumer consumer;
19 | private final AtomicInteger runningSearchCount = new AtomicInteger();
20 |
21 | public AuctionSearch_v4(Executor executor, List auctionHouses, AuctionSearchConsumer consumer) {
22 | this.executor = executor;
23 | this.auctionHouses = auctionHouses;
24 | this.consumer = consumer;
25 | }
26 |
27 | public void search(Set keywords) {
28 | runningSearchCount.set(auctionHouses.size());
29 |
30 | for (AuctionHouse auctionHouse : auctionHouses) {
31 | startSearching(auctionHouse, keywords);
32 | }
33 | }
34 |
35 | private void startSearching(final AuctionHouse auctionHouse, final Set keywords) {
36 | executor.execute(new Runnable() {
37 | public void run() {
38 | search(auctionHouse, keywords);
39 | }
40 | });
41 | }
42 |
43 | private void search(AuctionHouse auctionHouse, Set keywords) {
44 | // BUG1: THIS IS CORRECT
45 | List found = auctionHouse.findAuctions(keywords);
46 | if (!found.isEmpty()) {
47 | consumer.auctionSearchFound(found);
48 | }
49 |
50 | // BUG1: THIS IS INCORRECT
51 | //consumer.auctionSearchFound(auctionHouse.findAuctions(keywords));
52 |
53 | if (runningSearchCount.decrementAndGet() == 0) {
54 | consumer.auctionSearchFinished();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/testing-asynchronous-systems/src/book/example/async/notifications/NotificationTraceTests.java:
--------------------------------------------------------------------------------
1 | package book.example.async.notifications;
2 |
3 | import book.example.threading.races.MultithreadedStressTester;
4 | import org.junit.After;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import java.util.concurrent.Executors;
9 | import java.util.concurrent.ScheduledExecutorService;
10 | import java.util.concurrent.TimeUnit;
11 |
12 | import static org.hamcrest.Matchers.containsString;
13 | import static org.hamcrest.Matchers.equalTo;
14 | import static org.junit.Assert.assertThat;
15 | import static org.junit.Assert.fail;
16 |
17 | public class NotificationTraceTests {
18 | ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
19 | MultithreadedStressTester blitzer = new MultithreadedStressTester(100);
20 |
21 | @After
22 | public void stopScheduler() {
23 | scheduler.shutdownNow();
24 | }
25 |
26 | @Before
27 | public void startBlitzing() throws InterruptedException {
28 | blitzer.stress(new Runnable() {
29 | public void run() {
30 | trace.append("NOT-WANTED");
31 | try {
32 | Thread.sleep(10);
33 | } catch (InterruptedException e) {
34 | e.printStackTrace();
35 | }
36 | }
37 | });
38 | }
39 |
40 | @After
41 | public void stopBlitzer() {
42 | blitzer.shutdown();
43 | }
44 |
45 | NotificationTrace trace = new NotificationTrace();
46 |
47 | @Test(timeout = 500)
48 | public void waitsForMatchingMessage() throws InterruptedException {
49 | scheduler.schedule(new Runnable() {
50 | public void run() {
51 | trace.append("WANTED");
52 | }
53 | }, 100, TimeUnit.MILLISECONDS);
54 |
55 | trace.containsNotification(equalTo("WANTED"));
56 | }
57 |
58 | @Test
59 | public void failsIfNoMatchingMessageReceived() throws InterruptedException {
60 | try {
61 | trace.containsNotification(equalTo("WANTED"));
62 | }
63 | catch (AssertionError e) {
64 | assertThat("error message includes trace of messages received before failure",
65 | e.getMessage(), containsString("NOT-WANTED"));
66 | return;
67 | }
68 |
69 | fail("should have thrown AssertionError");
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/races/MultithreadedStressTester.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.races;
2 |
3 | import java.util.concurrent.*;
4 |
5 | import static java.util.concurrent.TimeUnit.MILLISECONDS;
6 |
7 | /**
8 | * A class that "blitzes" an object by calling it many times, from
9 | * multiple threads. Used for stress-testing synchronisation.
10 | *
11 | * @author nat
12 | */
13 | public class MultithreadedStressTester {
14 | /**
15 | * The default number of threads to run concurrently.
16 | */
17 | public static final int DEFAULT_THREAD_COUNT = 2;
18 |
19 | private final ExecutorService executor;
20 | private final int threadCount;
21 | private final int iterationCount;
22 |
23 |
24 | public MultithreadedStressTester(int iterationCount) {
25 | this(DEFAULT_THREAD_COUNT, iterationCount);
26 | }
27 |
28 | public MultithreadedStressTester(int threadCount, int iterationCount) {
29 | this.threadCount = threadCount;
30 | this.iterationCount = iterationCount;
31 | this.executor = Executors.newCachedThreadPool();
32 | }
33 |
34 | public MultithreadedStressTester(int threadCount, int iterationCount, ThreadFactory threadFactory) {
35 | this.threadCount = threadCount;
36 | this.iterationCount = iterationCount;
37 | this.executor = Executors.newCachedThreadPool(threadFactory);
38 | }
39 |
40 | public int totalActionCount() {
41 | return threadCount * iterationCount;
42 | }
43 |
44 | public void stress(final Runnable action) throws InterruptedException {
45 | spawnThreads(action).await();
46 | }
47 |
48 | public void blitz(long timeoutMs, final Runnable action) throws InterruptedException, TimeoutException {
49 | if (!spawnThreads(action).await(timeoutMs, MILLISECONDS)) {
50 | throw new TimeoutException("timed out waiting for blitzed actions to complete successfully");
51 | }
52 | }
53 |
54 | private CountDownLatch spawnThreads(final Runnable action) {
55 | final CountDownLatch finished = new CountDownLatch(threadCount);
56 |
57 | for (int i = 0; i < threadCount; i++) {
58 | executor.execute(new Runnable() {
59 | public void run() {
60 | try {
61 | repeat(action);
62 | }
63 | finally {
64 | finished.countDown();
65 | }
66 | }
67 | });
68 | }
69 | return finished;
70 | }
71 |
72 | private void repeat(Runnable action) {
73 | for (int i = 0; i < iterationCount; i++) {
74 | action.run();
75 | }
76 | }
77 |
78 | public void shutdown() {
79 | executor.shutdown();
80 | }
81 | }
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/builders/CustomerBuilder.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests.builders;
2 |
3 | import book.example.persistence.model.Address;
4 | import book.example.persistence.model.AuctionSiteCredentials;
5 | import book.example.persistence.model.Customer;
6 | import book.example.persistence.model.PaymentMethod;
7 |
8 | import java.util.HashSet;
9 | import java.util.Set;
10 |
11 | import static java.util.Arrays.asList;
12 | import static java.util.Collections.emptySet;
13 |
14 | public class CustomerBuilder extends AbstractBuilder {
15 | private String name = "customer";
16 | private String email = "customer@example.com";
17 | private Builder addressBuilder = new AddressBuilder();
18 | private Set> paymentMethods = emptySet();
19 | private Set> auctionSitesUsed = emptySet();
20 |
21 | public static CustomerBuilder aCustomer() {
22 | return new CustomerBuilder();
23 | }
24 |
25 | public Customer build() {
26 | return new Customer(name, email, addressBuilder.build(), buildSet(paymentMethods), buildSet(auctionSitesUsed));
27 | }
28 |
29 | public CustomerBuilder withName(String name) {
30 | CustomerBuilder other = this.clone();
31 | other.name = name;
32 | return other;
33 | }
34 |
35 | public CustomerBuilder withEmailAddress(String email) {
36 | CustomerBuilder other = this.clone();
37 | other.email = email;
38 | return other;
39 | }
40 |
41 | public CustomerBuilder withAddress(Builder addressBuilder) {
42 | CustomerBuilder other = this.clone();
43 | other.addressBuilder = addressBuilder;
44 | return other;
45 | }
46 |
47 | public CustomerBuilder withPaymentMethods(Builder extends PaymentMethod>... paymentMethodBuilders) {
48 | CustomerBuilder other = this.clone();
49 | other.paymentMethods = setOf(paymentMethodBuilders);
50 | return other;
51 | }
52 |
53 | public CustomerBuilder usingAuctionSites(Builder... auctionSiteLoginBuilders) {
54 | CustomerBuilder other = this.clone();
55 | other.auctionSitesUsed = setOf(auctionSiteLoginBuilders);
56 | return other;
57 | }
58 |
59 | private HashSet> setOf(Builder extends T>... builders) {
60 | return new HashSet>(asList(builders));
61 | }
62 |
63 | private static Set buildSet(Set> builders) {
64 | HashSet set = new HashSet();
65 |
66 | for (Builder extends T> builder : builders) {
67 | set.add(builder.build());
68 | }
69 |
70 | return set;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/testing-asynchronous-systems/src/book/example/async/notifications/NotificationTrace.java:
--------------------------------------------------------------------------------
1 | package book.example.async.notifications;
2 |
3 | import book.example.async.Timeout;
4 | import org.hamcrest.Matcher;
5 | import org.hamcrest.StringDescription;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class NotificationTrace {
11 | private final Object traceLock = new Object();
12 | private final List trace = new ArrayList();
13 | private long timeoutMs = 1000L;
14 |
15 | public long getTimeout() {
16 | return timeoutMs;
17 | }
18 |
19 | public void setTimeout(long newTimeoutMs) {
20 | this.timeoutMs = newTimeoutMs;
21 | }
22 |
23 | public void append(T message) {
24 | synchronized (traceLock) {
25 | trace.add(message);
26 | traceLock.notifyAll();
27 | }
28 | }
29 |
30 | public void containsNotification(Matcher super T> criteria)
31 | throws InterruptedException {
32 | Timeout timeout = new Timeout(timeoutMs);
33 |
34 | synchronized (traceLock) {
35 | NotificationStream stream = new NotificationStream(trace, criteria);
36 |
37 | while (!stream.hasMatched()) {
38 | if (timeout.hasTimedOut()) {
39 | throw new AssertionError(failureDescriptionFrom(criteria));
40 | }
41 |
42 | timeout.waitOn(traceLock);
43 | }
44 | }
45 | }
46 |
47 | private String failureDescriptionFrom(Matcher super T> acceptanceCriteria) {
48 | StringDescription description = new StringDescription();
49 |
50 | description.appendText("no message matching ")
51 | .appendDescriptionOf(acceptanceCriteria)
52 | .appendText("received within " + timeoutMs + "ms\n");
53 |
54 | if (trace.isEmpty()) {
55 | description.appendText("received nothing");
56 | } else {
57 | description.appendValueList("received:\n ", "\n ", "", trace);
58 | }
59 |
60 | return description.toString();
61 | }
62 |
63 | public static class NotificationStream {
64 | private final List notifications;
65 | private final Matcher super N> criteria;
66 | private int next = 0;
67 |
68 | public NotificationStream(List notifications, Matcher super N> criteria) {
69 | this.notifications = notifications;
70 | this.criteria = criteria;
71 | }
72 |
73 | public boolean hasMatched() {
74 | while (next < notifications.size()) {
75 | if (criteria.matches(notifications.get(next)))
76 | return true;
77 | next++;
78 | }
79 | return false;
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/neighbours/MoreThanImmediateNeighboursTest2.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.neighbours;
2 |
3 | import book.example.flexibility.neighbours.MoreThanImmediateNeighbours.*;
4 | import org.jmock.Expectations;
5 | import org.jmock.Mockery;
6 | import org.jmock.States;
7 | import org.jmock.integration.junit4.JMock;
8 | import org.jmock.integration.junit4.JUnit4Mockery;
9 | import org.junit.Test;
10 | import org.junit.runner.RunWith;
11 |
12 | import java.util.ArrayList;
13 |
14 | @RunWith(JMock.class)
15 | public class MoreThanImmediateNeighboursTest2 {
16 | final Mockery context = new JUnit4Mockery();
17 |
18 | final Connections connections = context.mock(Connections.class);
19 | final TicketManager ticketManager = context.mock(TicketManager.class);
20 | final IssueManager issueManager = context.mock(IssueManager.class);
21 | final IssueHandler issueHandler = context.mock(IssueHandler.class);
22 | final Issue issue1Unresolved = issue(true);
23 | final Issue issue2 = issue(false);
24 | final Issue issue3Unresolved = issue(true);
25 |
26 | final MoreThanImmediateNeighbours2 moreThanImmediateNeighbours = new MoreThanImmediateNeighbours2(connections);
27 |
28 | ///BEGIN more-than-immediate-neighbours-test
29 | @Test
30 | public void filtersUnresolvedIssuesFromIssueManager() throws Failure {
31 | final ArrayList allIssues = new ArrayList() {{
32 | add(issue1Unresolved);
33 | add(issue2);
34 | add(issue3Unresolved);
35 | }};
36 |
37 | final States locking = context.states("locking").startsAs("unlocked");
38 |
39 | context.checking(new Expectations() {{
40 | allowing(connections).getTicketManager();
41 | will(returnValue(ticketManager));
42 | allowing(issueManager).allIssuesIterator();
43 | will(returnIterator(allIssues));
44 |
45 | oneOf(ticketManager).lock();
46 | when(locking.is("unlocked"));
47 | then(locking.is("locked"));
48 |
49 | oneOf(ticketManager).getIssueManager();
50 | when(locking.is("locked"));
51 | will(returnValue(issueManager));
52 |
53 | oneOf(issueHandler).accept(issue1Unresolved);
54 | when(locking.is("locked"));
55 | oneOf(issueHandler).accept(issue3Unresolved);
56 | when(locking.is("locked"));
57 |
58 | oneOf(ticketManager).unlock();
59 | when(locking.is("locked"));
60 | then(locking.is("unlocked"));
61 | }});
62 |
63 | moreThanImmediateNeighbours.allUnresolvedIssues(issueHandler);
64 | }
65 | ///END more-than-immediate-neighbours-test
66 |
67 | private static Issue issue(final boolean isUnresolved) {
68 | return new Issue() {
69 | public boolean isUnresolved() {
70 | return isUnresolved;
71 | }
72 | };
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/neighbours/MoreThanImmediateNeighboursTest.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.neighbours;
2 |
3 | import book.example.flexibility.neighbours.MoreThanImmediateNeighbours.*;
4 | import org.jmock.Expectations;
5 | import org.jmock.Mockery;
6 | import org.jmock.States;
7 | import org.jmock.integration.junit4.JMock;
8 | import org.jmock.integration.junit4.JUnit4Mockery;
9 | import org.junit.Test;
10 | import org.junit.runner.RunWith;
11 |
12 | import java.util.ArrayList;
13 |
14 | @RunWith(JMock.class)
15 | public class MoreThanImmediateNeighboursTest {
16 | final Mockery context = new JUnit4Mockery();
17 |
18 | final Connections connections = context.mock(Connections.class);
19 | final TicketManager ticketManager = context.mock(TicketManager.class);
20 | final IssueManager issueManager = context.mock(IssueManager.class);
21 | final IssueHandler issueHandler = context.mock(IssueHandler.class);
22 | final Issue issue1Unresolved = issue(true);
23 | final Issue issue2 = issue(false);
24 | final Issue issue3Unresolved = issue(true);
25 |
26 | final MoreThanImmediateNeighbours moreThanImmediateNeighbours = new MoreThanImmediateNeighbours(connections);
27 |
28 | ///BEGIN more-than-immediate-neighbours-test
29 | @Test
30 | public void filtersUnresolvedIssuesFromIssueManager() throws Failure {
31 | final ArrayList allIssues = new ArrayList() {{
32 | add(issue1Unresolved);
33 | add(issue2);
34 | add(issue3Unresolved);
35 | }};
36 |
37 | final States locking = context.states("locking").startsAs("unlocked");
38 |
39 | context.checking(new Expectations() {{
40 | allowing(connections).getTicketManager();
41 | will(returnValue(ticketManager));
42 |
43 | oneOf(ticketManager).lock();
44 | then(locking.is("locked"));
45 | oneOf(ticketManager).getIssueManager();
46 | when(locking.is("locked"));
47 | will(returnValue(issueManager));
48 |
49 | oneOf(issueManager).allIssuesIterator();
50 | when(locking.is("locked"));
51 | will(returnValue(allIssues.iterator()));
52 |
53 | oneOf(issueHandler).accept(issue1Unresolved);
54 | when(locking.is("locked"));
55 |
56 | oneOf(issueHandler).accept(issue3Unresolved);
57 | when(locking.is("locked"));
58 |
59 | oneOf(ticketManager).unlock();
60 | when(locking.is("locked"));
61 | then(locking.is("unlocked"));
62 | }});
63 |
64 | moreThanImmediateNeighbours.allUnresolvedIssues(issueHandler);
65 | }
66 | ///END more-than-immediate-neighbours-test
67 |
68 | private static Issue issue(final boolean isUnresolved) {
69 | return new Issue() {
70 | public boolean isUnresolved() {
71 | return isUnresolved;
72 | }
73 | };
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/ordering/AuctionChannelTest.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.ordering;
2 |
3 | import book.example.flexibility.ordering.AuctionChannel.AuctionConnection;
4 | import book.example.flexibility.ordering.AuctionChannel.AuctionConnectionFinder;
5 | import book.example.flexibility.ordering.AuctionChannel.AuctionDescription;
6 | import org.jmock.Expectations;
7 | import org.jmock.Mockery;
8 | import org.jmock.Sequence;
9 | import org.jmock.integration.junit4.JMock;
10 | import org.jmock.integration.junit4.JUnit4Mockery;
11 | import org.junit.Test;
12 | import org.junit.runner.RunWith;
13 |
14 | import static java.util.Arrays.asList;
15 |
16 | @RunWith(JMock.class)
17 | public class AuctionChannelTest {
18 | private static final String MESSAGE_BODY = "a message";
19 | private final Mockery context = new JUnit4Mockery();
20 | private final AuctionDescription description = namedDescription("valid");
21 | private final AuctionDescription description0 = namedDescription("0");
22 | private final AuctionDescription description1 = namedDescription("1");
23 | private final AuctionConnection connection = context.mock(AuctionConnection.class);
24 | private final AuctionConnectionFinder connectionFinder = context.mock(AuctionConnectionFinder.class);
25 | private final AuctionChannel auctionChannel = new AuctionChannel(connectionFinder);
26 |
27 |
28 | @Test
29 | public void
30 | sendsMessageToValidConnection() {
31 | context.checking(new Expectations() {{
32 | allowing(connectionFinder).findConnectionFor(description);
33 | will(returnValue(connection));
34 |
35 | oneOf(connection).send(MESSAGE_BODY);
36 | }});
37 |
38 | auctionChannel.sendMessageTo(MESSAGE_BODY, asList(description));
39 | }
40 |
41 |
42 | @Test
43 | public void
44 | searchesConnectionsInOrder() {
45 | final Sequence connectionSearch = context.sequence("connection");
46 | context.checking(new Expectations() {{
47 | oneOf(connectionFinder).findConnectionFor(description0);
48 | inSequence(connectionSearch);
49 | will(returnValue(null));
50 | oneOf(connectionFinder).findConnectionFor(description1);
51 | inSequence(connectionSearch);
52 | will(returnValue(null));
53 | oneOf(connectionFinder).findConnectionFor(description);
54 | inSequence(connectionSearch);
55 | will(returnValue(connection));
56 |
57 | oneOf(connection).send(MESSAGE_BODY);
58 | }});
59 |
60 | auctionChannel.sendMessageTo(MESSAGE_BODY, asList(description0, description1, description));
61 | }
62 |
63 | private static AuctionDescription namedDescription(final String name) {
64 | return new AuctionDescription() {
65 | @Override
66 | public String toString() {
67 | return "Description: " + name;
68 | }
69 | };
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/custom-hamcrest-matcher/src/book/example/hamcrest/StringStartsWithMatcherTest.java:
--------------------------------------------------------------------------------
1 | package book.example.hamcrest;
2 |
3 | import org.hamcrest.Matcher;
4 | import org.hamcrest.StringDescription;
5 | import org.junit.Test;
6 |
7 | import static book.example.hamcrest.StringStartsWithMatcher.startsWith;
8 | import static org.hamcrest.Matchers.containsString;
9 | import static org.hamcrest.Matchers.equalTo;
10 | import static org.junit.Assert.*;
11 |
12 | public class StringStartsWithMatcherTest extends AbstractMatcherTest {
13 | static final String PREFIX = "PREFIX";
14 | Matcher stringStartsWith = startsWith(PREFIX);
15 |
16 | @Override
17 | protected Matcher> createMatcher() {
18 | return stringStartsWith;
19 | }
20 |
21 | @Test
22 | public void evaluatesToTrueIfArgumentStartsWithSpecifiedSubstring() {
23 | assertTrue("should be true if excerpt at beginning", stringStartsWith.matches(PREFIX + "END"));
24 | assertFalse("should be false if excerpt at end", stringStartsWith.matches("START" + PREFIX));
25 | assertFalse("should be false if excerpt in middle", stringStartsWith.matches("START" + PREFIX + "END"));
26 | assertTrue("should be true if excerpt is at beginning and repeated", stringStartsWith.matches(PREFIX + PREFIX));
27 |
28 | assertFalse("should be false if excerpt is not in string", stringStartsWith.matches("Something else"));
29 | assertFalse("should be false if part of excerpt is at start of string", stringStartsWith.matches(PREFIX.substring(1)));
30 | }
31 |
32 | @Test
33 | public void evaluatesToTrueIfArgumentIsEqualToSubstring() {
34 | assertTrue("should be true if excerpt is entire string", stringStartsWith.matches(PREFIX));
35 | }
36 |
37 | @Test
38 | public void hasAReadableDescription() {
39 | assertDescription("a string starting with \"PREFIX\"", stringStartsWith);
40 | }
41 |
42 | @Test
43 | public void describesMismatch() {
44 | StringDescription d = new StringDescription();
45 | stringStartsWith.describeMismatch("Bananas", d);
46 | assertThat(d.toString(), equalTo("started with \"Banana\""));
47 | }
48 |
49 | @Test
50 | public void describesMismatchAgainstShortString() {
51 | StringDescription d = new StringDescription();
52 | stringStartsWith.describeMismatch("Foo", d);
53 | assertThat(d.toString(), equalTo("started with \"Foo\""));
54 | }
55 |
56 | @Test
57 | public void describesMismatchAgainstNull() {
58 | StringDescription d = new StringDescription();
59 | stringStartsWith.describeMismatch(null, d);
60 | assertThat(d.toString(), equalTo("was null"));
61 | }
62 |
63 | @Test
64 | public void describesMismatchAgainstUnknownObjectType() {
65 | StringDescription d = new StringDescription();
66 | stringStartsWith.describeMismatch(new UnknownType(), d);
67 | assertThat(d.toString(), containsString(UnknownType.class.getName()));
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/SynchronisingImposteriser.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import org.jmock.api.Imposteriser;
4 | import org.jmock.api.Invocation;
5 | import org.jmock.api.Invokable;
6 | import org.jmock.internal.StatePredicate;
7 | import org.jmock.lib.JavaReflectionImposteriser;
8 | import org.junit.Assert;
9 |
10 | import static org.hamcrest.StringDescription.asString;
11 |
12 | /**
13 | * A Decorator that wraps an Imposteriser and makes the Mockery thread-safe.
14 | *
15 | * In the latest version of jMock, this is performed by plugging a Synchroniser into the Mockery
16 | *
17 | * @author Nat Pryce
18 | */
19 | public class SynchronisingImposteriser extends DecoratingImposteriser {
20 | private final Object sync = new Object();
21 | private Error firstError = null;
22 |
23 | public SynchronisingImposteriser() {
24 | this(JavaReflectionImposteriser.INSTANCE);
25 | }
26 |
27 | public SynchronisingImposteriser(Imposteriser imposteriser) {
28 | super(imposteriser);
29 | }
30 |
31 | /**
32 | * Waits for a StatePredicate to become active.
33 | *
34 | * Warning: this will wait forever unless the test itself has a timeout.
35 | *
36 | * @param p the StatePredicate to wait for
37 | * @throws InterruptedException
38 | */
39 | public void waitUntil(StatePredicate p) throws InterruptedException {
40 | synchronized (sync) {
41 | while (!p.isActive()) {
42 | checkForFailure();
43 | sync.wait();
44 | }
45 | }
46 | }
47 |
48 | /**
49 | * Waits up to a timeout for a StatePredicate to become active. Fails the test
50 | * if the timeout expires.
51 | *
52 | * @param p the StatePredicate to wait for
53 | * @param timeoutMs the timeout in milliseconds
54 | * @throws InterruptedException
55 | */
56 | public void waitUntil(StatePredicate p, long timeoutMs) throws InterruptedException {
57 | long start = System.currentTimeMillis();
58 |
59 | synchronized (sync) {
60 | while (!p.isActive()) {
61 | checkForFailure();
62 |
63 | long now = System.currentTimeMillis();
64 | long timeLeft = timeoutMs - (now - start);
65 |
66 | if (timeLeft <= 0) {
67 | Assert.fail("timeout waiting for " + asString(p));
68 | }
69 |
70 | sync.wait(timeLeft);
71 | }
72 | }
73 | }
74 |
75 | @Override
76 | protected Object applyInvocation(Invokable imposter, Invocation invocation) throws Throwable {
77 | synchronized (sync) {
78 | try {
79 | return imposter.invoke(invocation);
80 | } catch (Error e) {
81 | if (firstError == null) {
82 | firstError = e;
83 | }
84 |
85 | sync.notifyAll();
86 |
87 | throw e;
88 | } finally {
89 | sync.notifyAll();
90 | }
91 | }
92 | }
93 |
94 | private void checkForFailure() {
95 | if (firstError != null) {
96 | throw firstError;
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/testing-persistence/scripts/example-db.ddl:
--------------------------------------------------------------------------------
1 |
2 |
3 | CREATE TABLE CreditCardDetails (
4 | id INTEGER PRIMARY KEY,
5 | cardNumber VARCHAR(16) NOT NULL,
6 | nameOnCard VARCHAR(80) NOT NULL,
7 | expiryDate DATE NOT NULL,
8 | billingAddress_id INTEGER NOT NULL
9 | );
10 |
11 | CREATE TABLE PaymentMethod (
12 | id INTEGER PRIMARY KEY
13 | );
14 |
15 | CREATE TABLE Customer (
16 | id INTEGER PRIMARY KEY,
17 | name VARCHAR(80) NOT NULL,
18 | email VARCHAR(80),
19 | address_id INTEGER NOT NULL
20 | );
21 |
22 | CREATE TABLE Customer_PaymentMethod (
23 | customer_id INTEGER NOT NULL,
24 | paymentMethods_id INTEGER NOT NULL,
25 | PRIMARY KEY (customer_id, paymentMethods_id)
26 | );
27 |
28 | CREATE TABLE AuctionSite (
29 | id INTEGER PRIMARY KEY,
30 | name VARCHAR(32) NOT NULL,
31 | siteURL VARCHAR(255) NOT NULL
32 | );
33 |
34 | CREATE TABLE AuctionSiteCredentials (
35 | id INTEGER PRIMARY KEY,
36 | auctionSite_id INTEGER NOT NULL,
37 | userName VARCHAR(255) NOT NULL,
38 | password VARCHAR(255) NOT NULL
39 | );
40 |
41 |
42 | CREATE TABLE PayMateDetails (
43 | id INTEGER PRIMARY KEY,
44 | userName VARCHAR(255) NOT NULL,
45 | password VARCHAR(255) NOT NULL
46 | );
47 |
48 | CREATE TABLE Address (
49 | id INTEGER PRIMARY KEY,
50 | street VARCHAR(255),
51 | town VARCHAR(255),
52 | postcode VARCHAR(255),
53 | country VARCHAR(255)
54 | );
55 |
56 | CREATE TABLE Customer_AuctionSiteCredentials (
57 | customer_id INTEGER NOT NULL,
58 | auctionSiteLogins_id INTEGER NOT NULL,
59 |
60 | PRIMARY KEY (customer_id, auctionSiteLogins_id)
61 | );
62 |
63 | CREATE TABLE HIBERNATE_UNIQUE_KEY (
64 | next_hi INTEGER
65 | );
66 |
67 | -- ----------------------------------------------
68 | -- DDL Statements for keys
69 | -- ----------------------------------------------
70 |
71 | -- foreign
72 | ALTER TABLE Customer
73 | ADD CONSTRAINT F1
74 | FOREIGN KEY (Address_id)
75 | REFERENCES Address (id)
76 | ON DELETE CASCADE
77 | ON UPDATE NO ACTION;
78 |
79 | ALTER TABLE Customer_PaymentMethod
80 | ADD CONSTRAINT F2
81 | FOREIGN KEY (PaymentMethods_id)
82 | REFERENCES PaymentMethod (id)
83 | ON DELETE CASCADE
84 | ON UPDATE NO ACTION;
85 |
86 | ALTER TABLE Customer_PaymentMethod
87 | ADD CONSTRAINT F3
88 | FOREIGN KEY (customer_id)
89 | REFERENCES Customer (id)
90 | ON DELETE CASCADE
91 | ON UPDATE NO ACTION;
92 |
93 | ALTER TABLE Customer_AuctionSiteLogin
94 | ADD CONSTRAINT F4
95 | FOREIGN KEY (customer_id)
96 | REFERENCES Customer (id)
97 | ON DELETE CASCADE
98 | ON UPDATE NO ACTION;
99 |
100 | ALTER TABLE Customer_AuctionSiteLogin
101 | ADD CONSTRAINT F5
102 | FOREIGN KEY (auctionSiteLogins_id)
103 | REFERENCES AuctionSiteLogin (id)
104 | ON DELETE CASCADE
105 | ON UPDATE NO ACTION;
106 |
107 | ALTER TABLE PaymateDetails
108 | ADD CONSTRAINT F6
109 | FOREIGN KEY (id)
110 | REFERENCES PaymentMethod (id)
111 | ON DELETE CASCADE
112 | ON UPDATE NO ACTION;
113 |
114 | ALTER TABLE CreditCardDetails
115 | ADD CONSTRAINT F7
116 | FOREIGN KEY (id)
117 | REFERENCES PaymentMethod (ID)
118 | ON DELETE CASCADE
119 | ON UPDATE NO ACTION;
120 |
121 | ALTER TABLE CreditCardDetails
122 | ADD CONSTRAINT F8
123 | FOREIGN KEY (BillingAddress_id)
124 | REFERENCES Address (id)
125 | ON DELETE CASCADE
126 | ON UPDATE NO ACTION;
127 |
128 | INSERT INTO HIBERNATE_UNIQUE_KEY (next_hi) VALUES (0);
129 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearch_v2_Tests.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.StubAuctionHouse;
6 | import book.example.common.searching.async.AuctionSearchConsumer;
7 | import org.jmock.Expectations;
8 | import org.jmock.Mockery;
9 | import org.jmock.States;
10 | import org.jmock.integration.junit4.JMock;
11 | import org.jmock.integration.junit4.JUnit4Mockery;
12 | import org.jmock.lib.concurrent.DeterministicExecutor;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 |
16 | import java.util.Arrays;
17 | import java.util.HashSet;
18 | import java.util.List;
19 | import java.util.Set;
20 |
21 | import static java.util.Arrays.asList;
22 | import static java.util.Collections.emptyList;
23 |
24 | /**
25 | * Note: deterministic scheduler won't catch the synchronisation error in the
26 | * class under test. So, this makes it easier to test the functionality
27 | * of the class but you still need to stress test the synchronisation.
28 | */
29 | @RunWith(JMock.class)
30 | public class AuctionSearch_v2_Tests {
31 | final Mockery context = new JUnit4Mockery();
32 | final DeterministicExecutor executor = new DeterministicExecutor();
33 | final StubAuctionHouse houseA = new StubAuctionHouse("houseA");
34 | final StubAuctionHouse houseB = new StubAuctionHouse("houseB");
35 |
36 | List resultsFromA = asList(auction(houseA, "1"));
37 | List resultsFromB = asList(auction(houseB, "2"));
38 | ;
39 |
40 | final AuctionSearchConsumer consumer = context.mock(AuctionSearchConsumer.class);
41 | AuctionSearch_v3 search = new AuctionSearch_v3(executor, houses(houseA, houseB), consumer);
42 |
43 | @Test
44 | public void
45 | searchesAllAuctionHouses() throws Exception {
46 | final Set keywords = set("sheep", "cheese");
47 | houseA.willReturnSearchResults(keywords, resultsFromA);
48 | houseB.willReturnSearchResults(keywords, resultsFromB);
49 |
50 | context.checking(new Expectations() {{
51 | final States searching = context.states("searching");
52 |
53 | oneOf(consumer).auctionSearchFound(resultsFromA);
54 | when(searching.isNot("done"));
55 | oneOf(consumer).auctionSearchFound(resultsFromB);
56 | when(searching.isNot("done"));
57 | oneOf(consumer).auctionSearchFinished();
58 | then(searching.is("done"));
59 | }});
60 |
61 | search.search(keywords);
62 | executor.runUntilIdle();
63 | }
64 |
65 | @Test
66 | public void doesNotAnnounceEmptySearchResults() throws Exception {
67 | final Set keywords = set("keywords");
68 | houseA.willReturnSearchResults(keywords, resultsFromA);
69 | houseB.willReturnSearchResults(keywords, noResults());
70 |
71 | context.checking(new Expectations() {{
72 | oneOf(consumer).auctionSearchFound(resultsFromA);
73 | oneOf(consumer).auctionSearchFinished();
74 | }});
75 |
76 | search.search(keywords);
77 | executor.runUntilIdle();
78 | }
79 |
80 | private List noResults() {
81 | return emptyList();
82 | }
83 |
84 | private List houses(AuctionHouse... houses) {
85 | return asList(houses);
86 | }
87 |
88 | private AuctionDescription auction(AuctionHouse house, String id) {
89 | return new AuctionDescription(house, id, "test auction " + id);
90 | }
91 |
92 | private Set set(String... strings) {
93 | return new HashSet(Arrays.asList(strings));
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearchStressTests.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.StubAuctionHouse;
6 | import book.example.common.searching.async.AuctionSearchConsumer;
7 | import org.hamcrest.Matcher;
8 | import org.jmock.Expectations;
9 | import org.jmock.Mockery;
10 | import org.jmock.States;
11 | import org.jmock.integration.junit4.JMock;
12 | import org.jmock.integration.junit4.JUnit4Mockery;
13 | import org.jmock.lib.concurrent.Synchroniser;
14 | import org.junit.After;
15 | import org.junit.Test;
16 | import org.junit.runner.RunWith;
17 |
18 | import java.util.ArrayList;
19 | import java.util.HashSet;
20 | import java.util.List;
21 | import java.util.concurrent.ExecutorService;
22 | import java.util.concurrent.Executors;
23 |
24 | import static java.util.Arrays.asList;
25 | import static java.util.concurrent.TimeUnit.SECONDS;
26 | import static org.hamcrest.Matchers.anything;
27 |
28 | @RunWith(JMock.class)
29 | public class AuctionSearchStressTests {
30 | private static final HashSet KEYWORDS = new HashSet(asList("sheep", "cheese"));
31 | private static final int NUMBER_OF_AUCTION_HOUSES = 80;
32 | private static final int NUMBER_OF_SEARCHES = 20;
33 |
34 | Synchroniser synchroniser = new Synchroniser();
35 | Mockery context = new JUnit4Mockery() {{
36 | setThreadingPolicy(synchroniser);
37 | }};
38 |
39 |
40 | final AuctionSearchConsumer consumer = context.mock(AuctionSearchConsumer.class, "consumer");
41 | final States searching = context.states("searching");
42 |
43 | final ExecutorService executor = Executors.newCachedThreadPool();
44 |
45 | // Change to v2, v3, v4 to test different versions...
46 | AuctionSearch_v4 search = new AuctionSearch_v4(executor, auctionHouses(), consumer);
47 |
48 | @Test(timeout = 500)
49 | public void
50 | onlyOneAuctionSearchFinishedNotificationPerSearch() throws InterruptedException {
51 | context.checking(new Expectations() {{
52 | ignoring(consumer).auctionSearchFound(with(anyResults()));
53 | }});
54 |
55 | for (int i = 0; i < NUMBER_OF_SEARCHES; i++) {
56 | completeASearch();
57 | }
58 | }
59 |
60 | private void completeASearch() throws InterruptedException {
61 | searching.startsAs("in progress");
62 |
63 | context.checking(new Expectations() {{
64 | exactly(1).of(consumer).auctionSearchFinished();
65 | then(searching.is("done"));
66 | }});
67 |
68 | search.search(KEYWORDS);
69 |
70 | synchroniser.waitUntil(searching.is("done"));
71 | }
72 |
73 | private List auctionHouses() {
74 | ArrayList auctionHouses = new ArrayList();
75 |
76 | for (int i = 0; i < NUMBER_OF_AUCTION_HOUSES; i++) {
77 | auctionHouses.add(stubbedAuctionHouse(i));
78 | }
79 |
80 | return auctionHouses;
81 | }
82 |
83 | private AuctionHouse stubbedAuctionHouse(int i) {
84 | StubAuctionHouse house = new StubAuctionHouse("house" + i);
85 | house.willReturnSearchResults(
86 | KEYWORDS, asList(new AuctionDescription(house, "id" + i, "description")));
87 | return house;
88 | }
89 |
90 | @After
91 | public void cleanUp() throws InterruptedException {
92 | executor.shutdown();
93 | executor.awaitTermination(1, SECONDS);
94 | }
95 |
96 | private Matcher> anyResults() {
97 | return anything();
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearchTests_v3.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.StubAuctionHouse;
6 | import book.example.common.searching.async.AuctionSearchConsumer;
7 | import org.jmock.Expectations;
8 | import org.jmock.Mockery;
9 | import org.jmock.States;
10 | import org.jmock.integration.junit4.JMock;
11 | import org.jmock.integration.junit4.JUnit4Mockery;
12 | import org.jmock.lib.concurrent.DeterministicExecutor;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 |
16 | import java.util.Arrays;
17 | import java.util.HashSet;
18 | import java.util.List;
19 | import java.util.Set;
20 |
21 | import static java.util.Arrays.asList;
22 | import static java.util.Collections.emptyList;
23 |
24 | /**
25 | * Note: deterministic scheduler won't catch the synchronisation error in the
26 | * class under test. So, this makes it easier to test the functionality
27 | * of the class but you still need to stress test the synchronisation.
28 | */
29 | @RunWith(JMock.class)
30 | public class AuctionSearchTests_v3 {
31 | Mockery context = new JUnit4Mockery();
32 | AuctionSearchConsumer consumer = context.mock(AuctionSearchConsumer.class, "consumer");
33 |
34 | StubAuctionHouse auctionHouseA = new StubAuctionHouse("houseA");
35 | StubAuctionHouse auctionHouseB = new StubAuctionHouse("houseB");
36 |
37 | List resultsFromA = asList(auction(auctionHouseA, "1"), auction(auctionHouseA, "2"));
38 | List resultsFromB = asList(auction(auctionHouseB, "1"), auction(auctionHouseB, "2"));
39 |
40 | DeterministicExecutor executor = new DeterministicExecutor();
41 |
42 | AuctionSearch_v2 search = new AuctionSearch_v2(executor, houses(auctionHouseA, auctionHouseB), consumer);
43 |
44 | @Test
45 | public void searchesAuctionHouses() throws Exception {
46 | Set keywords = set("sheep", "cheese");
47 |
48 | auctionHouseA.willReturnSearchResults(keywords, resultsFromA);
49 | auctionHouseB.willReturnSearchResults(keywords, resultsFromB);
50 |
51 | context.checking(new Expectations() {{
52 | States searching = context.states("activity");
53 |
54 | oneOf(consumer).auctionSearchFound(resultsFromA);
55 | when(searching.isNot("finished"));
56 | oneOf(consumer).auctionSearchFound(resultsFromB);
57 | when(searching.isNot("finished"));
58 | oneOf(consumer).auctionSearchFinished();
59 | then(searching.is("finished"));
60 | }});
61 |
62 | search.search(keywords);
63 | executor.runUntilIdle();
64 | }
65 |
66 | @Test
67 | public void doesNotAnnounceEmptySearchResults() throws Exception {
68 | Set keywords = set("keywords");
69 |
70 | auctionHouseA.willReturnSearchResults(keywords, resultsFromA);
71 | auctionHouseB.willReturnSearchResults(keywords, noResults());
72 |
73 | context.checking(new Expectations() {{
74 | oneOf(consumer).auctionSearchFound(resultsFromA);
75 | oneOf(consumer).auctionSearchFinished();
76 | }});
77 |
78 | search.search(keywords);
79 | executor.runUntilIdle();
80 | }
81 |
82 | private List noResults() {
83 | return emptyList();
84 | }
85 |
86 | private List houses(AuctionHouse... houses) {
87 | return asList(houses);
88 | }
89 |
90 | private AuctionDescription auction(AuctionHouse house, String id) {
91 | return new AuctionDescription(house, id, "test auction " + id);
92 | }
93 |
94 | private Set set(String... strings) {
95 | return new HashSet(Arrays.asList(strings));
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearch_v3_Tests.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.StubAuctionHouse;
6 | import book.example.common.searching.async.AuctionSearchConsumer;
7 | import org.jmock.Expectations;
8 | import org.jmock.Mockery;
9 | import org.jmock.States;
10 | import org.jmock.integration.junit4.JMock;
11 | import org.jmock.integration.junit4.JUnit4Mockery;
12 | import org.jmock.lib.concurrent.DeterministicExecutor;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 |
16 | import java.util.Arrays;
17 | import java.util.HashSet;
18 | import java.util.List;
19 | import java.util.Set;
20 |
21 | import static java.util.Arrays.asList;
22 | import static java.util.Collections.emptyList;
23 |
24 | /**
25 | * Note: the deterministic scheduler won't catch the synchronisation error in the
26 | * class under test. So, taking control of scheduling makes it easier to test the functionality
27 | * of the class but we still need to stress test the synchronisation, which we do in the
28 | * {@link AuctionSearchStressTests}.
29 | */
30 | @RunWith(JMock.class)
31 | public class AuctionSearch_v3_Tests {
32 | Mockery context = new JUnit4Mockery();
33 | AuctionSearchConsumer consumer = context.mock(AuctionSearchConsumer.class, "consumer");
34 |
35 | StubAuctionHouse auctionHouseA = new StubAuctionHouse("houseA");
36 | StubAuctionHouse auctionHouseB = new StubAuctionHouse("houseB");
37 |
38 | List resultsFromA = asList(auction(auctionHouseA, "1"), auction(auctionHouseA, "2"));
39 | List resultsFromB = asList(auction(auctionHouseB, "1"), auction(auctionHouseB, "2"));
40 |
41 | DeterministicExecutor executor = new DeterministicExecutor();
42 |
43 | AuctionSearch_v2 search = new AuctionSearch_v2(executor, houses(auctionHouseA, auctionHouseB), consumer);
44 |
45 | @Test
46 | public void searchesAuctionHouses() throws Exception {
47 | Set keywords = set("sheep", "cheese");
48 |
49 | auctionHouseA.willReturnSearchResults(keywords, resultsFromA);
50 | auctionHouseB.willReturnSearchResults(keywords, resultsFromB);
51 |
52 | context.checking(new Expectations() {{
53 | States searching = context.states("activity");
54 |
55 | oneOf(consumer).auctionSearchFound(resultsFromA);
56 | when(searching.isNot("finished"));
57 | oneOf(consumer).auctionSearchFound(resultsFromB);
58 | when(searching.isNot("finished"));
59 | oneOf(consumer).auctionSearchFinished();
60 | then(searching.is("finished"));
61 | }});
62 |
63 | search.search(keywords);
64 | executor.runUntilIdle();
65 | }
66 |
67 | @Test
68 | public void doesNotAnnounceEmptySearchResults() throws Exception {
69 | Set keywords = set("keywords");
70 |
71 | auctionHouseA.willReturnSearchResults(keywords, resultsFromA);
72 | auctionHouseB.willReturnSearchResults(keywords, noResults());
73 |
74 | context.checking(new Expectations() {{
75 | oneOf(consumer).auctionSearchFound(resultsFromA);
76 | oneOf(consumer).auctionSearchFinished();
77 | }});
78 |
79 | search.search(keywords);
80 | executor.runUntilIdle();
81 | }
82 |
83 | private List noResults() {
84 | return emptyList();
85 | }
86 |
87 | private List houses(AuctionHouse... houses) {
88 | return asList(houses);
89 | }
90 |
91 | private AuctionDescription auction(AuctionHouse house, String id) {
92 | return new AuctionDescription(house, id, "test auction " + id);
93 | }
94 |
95 | private Set set(String... strings) {
96 | return new HashSet(Arrays.asList(strings));
97 | }
98 | }
--------------------------------------------------------------------------------
/testing-multithreaded-code/src/book/example/threading/executor/AuctionSearch_v1_Tests.java:
--------------------------------------------------------------------------------
1 | package book.example.threading.executor;
2 |
3 | import book.example.common.searching.AuctionDescription;
4 | import book.example.common.searching.AuctionHouse;
5 | import book.example.common.searching.StubAuctionHouse;
6 | import book.example.common.searching.async.AuctionSearchConsumer;
7 | import org.jmock.Expectations;
8 | import org.jmock.Mockery;
9 | import org.jmock.States;
10 | import org.jmock.integration.junit4.JMock;
11 | import org.jmock.integration.junit4.JUnit4Mockery;
12 | import org.jmock.lib.concurrent.Synchroniser;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 |
16 | import java.util.Arrays;
17 | import java.util.HashSet;
18 | import java.util.List;
19 | import java.util.Set;
20 |
21 | import static java.util.Arrays.asList;
22 | import static java.util.Collections.emptyList;
23 |
24 | @RunWith(JMock.class)
25 | public class AuctionSearch_v1_Tests {
26 | Synchroniser synchroniser = new Synchroniser();
27 |
28 | Mockery context = new JUnit4Mockery() {{
29 | setThreadingPolicy(synchroniser);
30 | }};
31 |
32 | AuctionSearchConsumer consumer = context.mock(AuctionSearchConsumer.class, "consumer");
33 |
34 | StubAuctionHouse auctionHouseA = new StubAuctionHouse("houseA");
35 | StubAuctionHouse auctionHouseB = new StubAuctionHouse("houseB");
36 |
37 | AuctionSearch_v1 search = new AuctionSearch_v1(houses(auctionHouseA, auctionHouseB), consumer);
38 |
39 | Set keywords = set("sheep", "cheese");
40 | List resultsFromA = asList(auction(auctionHouseA, "1"), auction(auctionHouseA, "2"));
41 | List resultsFromB = asList(auction(auctionHouseB, "1"), auction(auctionHouseB, "2"));
42 |
43 | States searching = context.states("activity");
44 |
45 | @Test(timeout = 100)
46 | public void searchesAuctionHouses() throws Exception {
47 | auctionHouseA.willReturnSearchResults(keywords, resultsFromA);
48 | auctionHouseB.willReturnSearchResults(keywords, resultsFromB);
49 |
50 | context.checking(new Expectations() {{
51 | oneOf(consumer).auctionSearchFound(resultsFromA);
52 | when(searching.isNot("finished"));
53 | oneOf(consumer).auctionSearchFound(resultsFromB);
54 | when(searching.isNot("finished"));
55 | oneOf(consumer).auctionSearchFinished();
56 | then(searching.is("finished"));
57 | }});
58 |
59 | search.search(keywords);
60 |
61 | waitForSearchToFinish();
62 | }
63 |
64 | @Test(timeout = 100)
65 | public void doesNotAnnounceEmptySearchResults() throws Exception {
66 | Set keywords = set("keywords");
67 |
68 | auctionHouseA.willReturnSearchResults(keywords, resultsFromA);
69 | auctionHouseB.willReturnSearchResults(keywords, noResults());
70 |
71 | context.checking(new Expectations() {{
72 | oneOf(consumer).auctionSearchFound(resultsFromA);
73 | oneOf(consumer).auctionSearchFinished();
74 | then(searching.is("finished"));
75 | }});
76 |
77 | search.search(keywords);
78 |
79 | waitForSearchToFinish();
80 | }
81 |
82 |
83 | // more reliable and meaningful than a call to Thread.sleep
84 | private void waitForSearchToFinish() throws InterruptedException {
85 | synchroniser.waitUntil(searching.is("finished"));
86 | }
87 |
88 | private List noResults() {
89 | return emptyList();
90 | }
91 |
92 | private List houses(AuctionHouse... houses) {
93 | return asList(houses);
94 | }
95 |
96 | private AuctionDescription auction(AuctionHouse house, String id) {
97 | return new AuctionDescription(house, id, "test auction " + id);
98 | }
99 |
100 | private Set set(String... strings) {
101 | return new HashSet(Arrays.asList(strings));
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/flexibility/src/book/example/flexibility/ordering/AuctionSearcherTest.java:
--------------------------------------------------------------------------------
1 | package book.example.flexibility.ordering;
2 |
3 | import book.example.flexibility.ordering.AuctionSearcher.Auction;
4 | import book.example.flexibility.ordering.AuctionSearcher.AuctionSearchListener;
5 | import org.jmock.Expectations;
6 | import org.jmock.Mockery;
7 | import org.jmock.Sequence;
8 | import org.jmock.States;
9 | import org.jmock.integration.junit4.JMock;
10 | import org.jmock.integration.junit4.JUnit4Mockery;
11 | import org.junit.Test;
12 | import org.junit.runner.RunWith;
13 |
14 | import java.util.HashSet;
15 |
16 | import static java.util.Arrays.asList;
17 |
18 | @RunWith(JMock.class)
19 | public class AuctionSearcherTest {
20 | private static final Auction STUB_AUCTION2 = stubAuctionToMatch("word2");
21 | private static final Auction STUB_AUCTION1 = stubAuctionToMatch("word1");
22 | private static final HashSet KEYWORDS = new HashSet(asList("word1", "word2"));
23 | private final Mockery context = new JUnit4Mockery();
24 | private final AuctionSearchListener searchListener = context.mock(AuctionSearchListener.class);
25 |
26 | @Test
27 | public void
28 | announcesMatchForOneAuction_NoOrdering() {
29 | final AuctionSearcher auctionSearch = new AuctionSearcher(searchListener, asList(STUB_AUCTION1));
30 |
31 | context.checking(new Expectations() {{
32 | oneOf(searchListener).searchMatched(STUB_AUCTION1);
33 | oneOf(searchListener).searchFinished();
34 | }});
35 |
36 | auctionSearch.searchFor(KEYWORDS);
37 | }
38 |
39 | @Test
40 | public void
41 | announcesMatchForOneAuction_Sequence() {
42 | final AuctionSearcher auctionSearch = new AuctionSearcher(searchListener, asList(STUB_AUCTION1));
43 |
44 | context.checking(new Expectations() {{
45 | Sequence events = context.sequence("events");
46 |
47 | oneOf(searchListener).searchMatched(STUB_AUCTION1);
48 | inSequence(events);
49 | oneOf(searchListener).searchFinished();
50 | inSequence(events);
51 | }});
52 |
53 | auctionSearch.searchFor(KEYWORDS);
54 | }
55 |
56 |
57 | @Test
58 | public void
59 | announcesMatchForTwoAuctions_Sequence() {
60 | final AuctionSearcher auctionSearch = new AuctionSearcher(searchListener, asList(STUB_AUCTION1, STUB_AUCTION2));
61 |
62 | context.checking(new Expectations() {{
63 | Sequence events = context.sequence("events");
64 |
65 | oneOf(searchListener).searchMatched(STUB_AUCTION1);
66 | inSequence(events);
67 | oneOf(searchListener).searchMatched(STUB_AUCTION2);
68 | inSequence(events);
69 | oneOf(searchListener).searchFinished();
70 | inSequence(events);
71 | }});
72 |
73 | auctionSearch.searchFor(KEYWORDS);
74 | }
75 |
76 |
77 | @Test
78 | public void
79 | announcesMatchForTwoAuctions_States() {
80 | final AuctionSearcher auctionSearch = new AuctionSearcher(searchListener, asList(STUB_AUCTION1, STUB_AUCTION2));
81 |
82 | context.checking(new Expectations() {{
83 | States searching = context.states("searching");
84 |
85 | oneOf(searchListener).searchMatched(STUB_AUCTION1);
86 | when(searching.isNot("finished"));
87 | oneOf(searchListener).searchMatched(STUB_AUCTION2);
88 | when(searching.isNot("finished"));
89 | oneOf(searchListener).searchFinished();
90 | then(searching.is("finished"));
91 | }});
92 |
93 | auctionSearch.searchFor(KEYWORDS);
94 | }
95 |
96 | private static Auction stubAuctionToMatch(final String match) {
97 | return new Auction() {
98 | public boolean matches(String keyword) {
99 | return match.equals(keyword);
100 | }
101 |
102 | @Override
103 | public String toString() {
104 | return "Auction for " + match;
105 | }
106 |
107 | ;
108 | };
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/testing-persistence/src/book/example/persistence/tests/PersistabilityTest.java:
--------------------------------------------------------------------------------
1 | package book.example.persistence.tests;
2 |
3 | import book.example.persistence.tests.builders.*;
4 | import org.junit.After;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import javax.persistence.EntityManager;
9 | import javax.persistence.EntityManagerFactory;
10 | import javax.persistence.Persistence;
11 | import javax.persistence.PersistenceException;
12 | import java.util.Arrays;
13 | import java.util.List;
14 |
15 | import static book.example.persistence.tests.PersistenceReflection.assertHaveSamePersistentFields;
16 | import static book.example.persistence.tests.PersistenceReflection.idOf;
17 | import static org.junit.Assert.assertNotNull;
18 |
19 | public class PersistabilityTest {
20 | final EntityManagerFactory factory = Persistence.createEntityManagerFactory("example");
21 | final EntityManager entityManager = factory.createEntityManager();
22 | final JPATransactor transactor = new JPATransactor(entityManager);
23 |
24 | @Before
25 | public void cleanDatabase() throws Exception {
26 | new DatabaseCleaner(entityManager).clean();
27 | }
28 |
29 | @After
30 | public void tearDown() {
31 | entityManager.close();
32 | factory.close();
33 | }
34 |
35 | @SuppressWarnings("unchecked")
36 | final List extends Builder>> persistentObjectBuilders = Arrays.asList(
37 | new AddressBuilder(),
38 | new PayMateDetailsBuilder(),
39 | new CreditCardDetailsBuilder(),
40 | new AuctionSiteBuilder(),
41 | new AuctionSiteLoginBuilder().forSite(persisted(new AuctionSiteBuilder())),
42 | new CustomerBuilder()
43 | .usingAuctionSites(
44 | new AuctionSiteLoginBuilder().forSite(persisted(new AuctionSiteBuilder())))
45 | .withPaymentMethods(
46 | new CreditCardDetailsBuilder(),
47 | new PayMateDetailsBuilder()));
48 |
49 | @Test
50 | public void canRoundTripPersistentObjects() throws Exception {
51 | for (Builder> builder : persistentObjectBuilders) {
52 | assertCanBePersisted(builder);
53 | }
54 | }
55 |
56 | private void assertCanBePersisted(Builder> builder) throws Exception {
57 | try {
58 | assertReloadsWithSameStateAs(persistedObjectFrom(builder));
59 | }
60 | catch (PersistenceException e) {
61 | throw new PersistenceException("could not round-trip " + typeFor(builder), e);
62 | }
63 | }
64 |
65 | private String typeFor(Builder> builder) {
66 | return builder.getClass().getSimpleName().replace("Builder", "");
67 | }
68 |
69 | private Object persistedObjectFrom(final Builder> builder) throws Exception {
70 | return transactor.performQuery(new QueryUnitOfWork