資料內(nèi)容:
Categories
Fitness functions exist across a variety of categories related to their scope, cadence, result,
invocation, proactivity, and coverage.
Scope: Atomic Versus Holistic
Atomic fitness functions run against a singular context and exercise one particular aspect of the
architecture. An excellent example of an atomic fitness function is a unit test that verifies some
architectural characteristic, such as modular coupling (we show an example of this type of fitness
function in Chapter 4). Thus, some application-level testing falls under the heading of fitness
functions, but not all unit tests serve as fitness functions—only the ones that verify architecture
characteristic(s). The example in Figure 2-3 represents an atomic fitness function: it checks only
for the presence of cycles between components.
For some architectural characteristics, developers must test more than each architectural
dimension in isolation. Holistic fitness functions run against a shared context and exercise a
combination of architectural aspects. Developers design holistic fitness functions to ensure that
combined features that work atomically don’t break in real-world combinations. For example,
imagine an architecture has fitness functions around both security and scalability. One of the key
items the security fitness function checks is staleness of data, and a key item for the scalability
tests is number of concurrent users within a certain latency range. To achieve scalability,
developers implement caching, which allows the atomic scalability fitness function to pass.
When caching isn’t turned on, the security fitness function passes. However, when run
holistically, enabling caching makes data too stale to pass the security fitness function, and the
holistic test fails.
We obviously cannot test every possible combination of architecture elements, so architects use
holistic fitness functions selectively to test important interactions. This selectivity and
prioritization also allows architects and developers to assess the difficulty in implementing a
particular testing scenario, thus allowing an assessment of how valuable that characteristic is.
Frequently, the interactions between architectural concerns determine the quality of the
architecture, which holistic fitness functions address.Cadence: Triggered Versus Continual Versus Temporal
Execution cadence is another distinguishing factor between fitness functions. Triggered fitness
functions run based on a particular event, such as a developer executing a unit test, a deployment
pipeline running unit tests, or a QA person performing exploratory testing. This encompasses
traditional testing, such as unit, functional, and behavior-driven development (BDD) testing,
among others.
Continual tests don’t run on a schedule but instead execute constant verification of architectural
aspect(s), such as transaction speed. For example, consider a microservices architecture in which
the architects want to build a fitness function around transaction time—how long it takes for a
transaction to complete, on average. Building any kind of triggered test provides sparse
information about real-world behavior. Thus, architects build a continual fitness function that
simulates a transaction in production while all the other real transactions run, often using a
technique called synthetic transactions. This allows developers to verify behavior and gather real
data about the system “in the wild.”