Posted on 4 mins read

In this series, I consolidate points from the GOOSGBT book and may comment on some of them. The post may not be coherent as I am extracting fragments I consider useful or enlightening.

Stackoverflow post to read: link

Levels of testing

  • Acceptance: Does the whole system work?
  • Integration: Does our code work against code we can’t change?
  • Unit: Do our objects do the right thing, are they convenient to work with?

Support for TDD with mock objects

The essential steps for creating a test:

  • Create any required mock objects.
  • Create any real objects, including the target object.
  • Specify how you expect the mock objects to be called by the target object.
  • Call the triggering method(s) on the target object.
  • Assert that any resulting values are valid and that all the expected calls have been made.

The important point, as we stress repeatedly throughout this book, is to make clear the intention of every test, distinguishing between the tested functionality, the supporting infrastructure, and the object structure.

Test Fixture

A test fixture is the fixed state that exists at the start of a test. A test fixture ensures that a test is repeatable—every time a test is run it starts in the same state so it should produce the same results. A fixture may be set up before the test runs and torn down after it has finished. Think of @Before and @After.

Mocking

Notes here are for jMock2. In the neigbourhood of page 26.

A mockery represents the context of the object under test, its neighboring objects; mock objects stand in for the real neighbors of the object under test while the test runs; and expectations describe how the object under test should invoke its neighbors during the test.

Note that the test does not require any assertions. This is quite common in mock object tests.

Walking Skeleton

We can’t automate the build, deploy, and test cycle without some idea of the overall structure. We don’t need much detail yet, just a broad-brush picture of what major system components will be needed to support the first planned release and how they will communicate.

We need a high-level view of the client’s requirements, both functional and non- functional, to guide our choices.

Unit-Test Behaviour Not Methods

Many developers who adopt TDD find their early tests hard to understand when they revisit them later, and one common mistake is thinking about testing methods. A test called testBidAccepted() tells us what it does, but not what it’s for.

We do better when we focus on the features that the object under test should provide, each of which may require collaboration with its neighbors and calling more than one of its methods. We need to know how to use the class to achieve a goal, *not how to exercise all the paths through its code*.

sniperJoinsAuctionUntilAuctionCloses()

Object - Oriented Style

We value code that is easy to maintain over code that is easy to write.1 Imple- menting a feature in the most direct way can damage the maintainability of the system, for example by making the code difficult to understand or by introducing hidden dependencies between components. Balancing immediate and longer-term concerns is often tricky, but we’ve seen too many teams that can no longer deliver because their system is too brittle.

We don’t want technical concepts to leak into the application model, so we write interfaces to describe its relationships with the outside world in its terminology (Cockburn’s ports). Then we write bridges between the application core and each technical domain (Cockburn’s adapters). This is related to what Eric Evans calls an “anticorruption layer” [Evans03].

Achieving Object Oriented Design

Breaking off, Budding out, Bundling up

Budding Out.

We think of this as “on-demand” design: we “pull” interfaces and their imple- mentations into existence from the needs of the client, rather than “pushing” out the features that we think a class should provide.

Building up to higher level programming

The declarative layer describes what the code will do, while the implementation layer describes how the code does it. The declarative layer is, in effect, a small domain-specific language embedded (in this case) in Java.

Building on Third Party Code

Only mock objects you own

When we use third-party code we often do not have a deep understanding of how it works. Even if we have the source available, we rarely have time to read it thoroughly enough to explore all its quirks. We can read its documentation, which is often incomplete or incorrect.

Yeah tell me about it.

Part 2 will be on the worked example.