carlin
Test doubles for Java: stubbed answers and verified calls.
Creates test doubles, supplies their answers and verifies calls made to them.
Key Concepts
Stubbing
Role. Doubles.mock accepts interfaces and extensible classes. Unstubbed calls return zero, false, supported empty containers or null. Use Doubles.stub(call) for successive return values, exceptions or computed answers; the final answer repeats. An Answer states the answer before the call, for void methods or restubbing without executing an existing answer: returning, throwing, answering, nothing or real, then of(double).call().
Arguments and verification
Role. Arguments match by value, with arrays compared by contents. If one argument uses an Argument matcher, all must: use eq for literal values. any() includes null; typed matchers do not. A confirmation.Confirmation is the receiver, as an Answer is: once().of(double).call() confirms the call made on what of returns and throws Braindropping on mismatch. A Frequency (once, times, never, atLeastOnce, atMost) confirms how often the call was made. Stubbing and confirmation expressions do not count as calls.
Order, capture and waiting
Role. Confirmation.ordered(doubles) is the Ordered confirmation: each of(double).call() must have been made after the one confirmed before it. Capturer.capturer retains matched arguments. Timeout.timeout(milliseconds) gives a Frequency that waits: once() or atLeast(n). Confirmation.noInteractions requires no calls; noMoreInteractions, on Confirmation for doubles or on an Ordered, requires every call to have been confirmed.
Usage
Stub a lookup and verify a write
import software.visionary.carlin.Capturer;
import static software.visionary.carlin.Doubles.mock;
import static software.visionary.carlin.Doubles.stub;
import static software.visionary.carlin.Answer.real;
import static software.visionary.carlin.confirmation.Confirmation.noMoreInteractions;
import static software.visionary.carlin.confirmation.Frequency.once;
public class DoubleExample {
public interface Shelf {
String titleAt(int index);
void shelve(String title);
default String first() { return titleAt(0); }
}
public static void main(String[] args) {
Shelf shelf = mock(Shelf.class);
stub(shelf.titleAt(0)).returning("First").returning("Second");
real().of(shelf).first();
System.out.println(shelf.first());
shelf.shelve("Book");
var title = Capturer.capturer(String.class);
once().of(shelf).shelve(title.capture());
System.out.println(title.value());
once().of(shelf).first();
once().of(shelf).titleAt(0);
noMoreInteractions(shelf);
}
}
Dependencies
software.visionary.contrax:enforcements:2026.10.13at Providedsoftware.visionary:junit-closure:2026.10.13at Testing
Caveats
- Final, sealed, record, enum, primitive and array types cannot be doubled. A class double runs its public or protected constructor with the fewest parameters, using zero and null arguments; final methods execute real code. Real default methods require a public interface in an accessible package.
Answer.realsupports interface defaults only.
Views
Drawn from the release. A link in a view opens its source at the release tag.