Introduction

Stubit

Stubit is a collection of extremely simple stubs to replace typical infrastructure dependencies.

To review the code, file issues or suggest changes, please visit the project’s GitHub page.

Getting Started

Requirements

In oder to use Stubit you need a JDK 17 or higher.

Dependencies

To use Stubit in your own project, you need to add it as a dependency to your project.

Gradle
implementation 'org.stubit:http:0.8.2'
Gradle.kts
implementation("org.stubit:http:0.8.2")
Maven
<dependency>
  <groupId>org.stubit</groupId>
  <artifactId>http</artifactId>
  <version>0.8.2</version>
</dependency>
The http is an example module.

Bill of Materials (BOM)

If you want to use more than one module in the same project, you can use Stubit’s bill of materials (BOM) and omit the explicit version for the other modules.

Gradle
implementation platform('org.stubit:bom:0.8.2')
implementation 'org.stubit:http'
Gradle.kts
implementation(platform("org.stubit:bom:0.8.2"))
implementation("org.stubit:http")
Maven
<project>
  <!--…-->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.stubit</groupId>
        <artifactId>bom</artifactId>
        <version>0.8.2</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <!-- … -->
  <dependencies>
    <dependency>
      <groupId>org.stubit</groupId>
      <artifactId>http</artifactId>
    </dependency>
  </dependencies>
  <!-- … -->
</project>

HTTP

The HTTP module contains a simple HTTP server, which can be started locally to stub an HTTP service.

Create and Start the Stub

Instantiating the HttpStub class automatically starts the stub at a random local port.

Java
try (var httpStub = new HttpStub()) {
  String stubAddress = httpStub.address();

  assertThat(stubAddress).isNotNull().startsWith("http://localhost:");
}
Kotlin
HttpStub().use { httpStub ->
  val stubAddress = httpStub.address()

  assertThat(stubAddress).isNotNull().startsWith("http://localhost:")
}

You can get its address via the address method

Java
String stubAddress = httpStub.address();
Kotlin
val stubAddress = httpStub.address()

Unstubbed Behaviour

By default, the stub will return a 404 response for any path and any method but POST.

Java
var request = new Request.Builder().url(httpStub.address() + "/nothing/here").build();
var response = okHttpClient.newCall(request).execute();

assertThat(response.code()).isEqualTo(404);
assertThat(response.body().string()).isEqualTo("No stubbing for GET /nothing/here");
Kotlin
val request = Request.Builder().url("${httpStub.address()}/nothing/here").build()
val response = okHttpClient.newCall(request).execute()

assertThat(response.code).isEqualTo(404)
assertThat(response.body!!.string()).isEqualTo("No stubbing for GET /nothing/here")

POST Requests

POST requests will by default return a 201 response for any path.

Java
var postRequest =
    new Request.Builder()
        .url(httpStub.address() + "/nothing/here")
        .post(RequestBody.create("Hello".getBytes(StandardCharsets.UTF_8)))
        .build();
var postResponse = okHttpClient.newCall(postRequest).execute();

assertThat(postResponse.code()).isEqualTo(201);
assertThat(postResponse.body().string()).isEqualTo("Added stubbing for /nothing/here");
assertThat(postResponse.header("Location")).startsWith("http://localhost");
Kotlin
val postRequest =
    Request.Builder()
        .url("${httpStub.address()}/nothing/here")
        .post("Hello".toRequestBody())
        .build()
val postResponse = okHttpClient.newCall(postRequest).execute()

assertThat(postResponse.code).isEqualTo(201)
assertThat(postResponse.body!!.string()).isEqualTo("Added stubbing for /nothing/here")
assertThat(postResponse.header("Location")).startsWith("http://localhost")

The body of the request will be returned for subsequent GET requests.

Java
var request = new Request.Builder().url(postResponse.header("Location")).build();
var response = okHttpClient.newCall(request).execute();

assertThat(response.code()).isEqualTo(200);
assertThat(response.body().string()).isEqualTo("Hello");
Kotlin
val request = Request.Builder().url(postResponse.header("Location")!!).build()
val response = okHttpClient.newCall(request).execute()

assertThat(response.code).isEqualTo(200)
assertThat(response.body!!.string()).isEqualTo("Hello")
This behaviour is likely to change in future releases!

Stub a Response

You can create a stubbing via the Stubbing.stub() method

Java
Stubbing stubbing =
    Stubbing.stub()
        .path("/some/where") (1)
        .method("GET") (2)
        .returns(StubbedResponse.response().body("Hello").statusCode(200)); (3)
1 Specifies the path for the stubbing.
2 Specifies the method.
3 Specifies the response that will be returned.
Kotlin
val stubbing =
    Stubbing.stub()
        .path("/some/where") (1)
        .method("GET") (2)
        .returns(StubbedResponse.response().body("Hello").statusCode(200)) (3)
1 Specifies the path for the stubbing.
2 Specifies the method.
3 Specifies the response that will be returned.

The Stubbing then needs to be added via the add method

Java
httpStub.add(stubbing);
Kotlin
httpStub.add(stubbing)

Further requests matching the Stubbing will now return the StubbedRequest instead of the default response.

Java
var request = new Request.Builder().url(httpStub.address() + "/some/where").build();
var response = okHttpClient.newCall(request).execute();

assertThat(response.code()).isEqualTo(200);
assertThat(response.body().string()).isEqualTo("Hello");
Kotlin
val request = Request.Builder().url("${httpStub.address()}/some/where").build()
val response = okHttpClient.newCall(request).execute()

assertThat(response.code).isEqualTo(200)
assertThat(response.body!!.string()).isEqualTo("Hello")

Spring Data

The Spring Data module contains stub implementation of the Spring Data repository interfaces, which can be used to replace actual database access in tests.

For instance, if we want to create a test for a service, which injects a CrudRepository, we can simply use a CrudRepositoryStub instead of a real repository.

Create the Stub

Let’s assume we have a service TestService, which injects a Spring Data CrudRepository named TestCrudRepository:

Java
class TestService {

  private final TestCrudRepository repository;

  @Autowired
  public TestService(TestCrudRepository repository) {
    this.repository = repository;
  }

  public List<TestEntity> getAll() {
    return stream(repository.findAll().spliterator(), false).toList();
  }

  public TestEntity getByName(String name) {
    return repository.findByName(name).orElseThrow();
  }
}
Kotlin
class TestService(
  private val repository: TestCrudRepository
) {

  fun getAll() = repository.findAll().toList()

  fun getByName(name: String) = repository.findByName(name)!!
}

We want to test this service without accessing the database and without specifying its internal behaviour (via a Mock).

TestCrudRepository is a typical Spring Data repository interface with only one additional method findByName:

Java
interface TestCrudRepository extends CrudRepository<TestEntity, UUID> {

  Optional<TestEntity> findByName(String name);
}
Kotlin
interface TestCrudRepository : CrudRepository<TestEntity, UUID> {

  fun findByName(name: String): TestEntity?
}

In oder to create a stub, we need to implement this interface. By extending from the CrudRepositoryStub, this only requires to implement the findByName method:

Java
class TestCrudRepositoryStub extends CrudRepositoryStub<TestEntity, UUID>
    implements TestCrudRepository {

  @Override
  public Optional<TestEntity> findByName(String name) {
    return data.values().stream().filter(e -> e.getName().equals(name)).findFirst();
  }
}
Kotlin
class TestCrudRepositoryStub : CrudRepositoryStub<TestEntity, UUID>(), TestCrudRepository {

  override fun findByName(name: String): TestEntity? {
    return data.values.find { e -> e.name.equals(name) }
  }
}

Use the Stub

In a test we can now use the TestCrudRepositoryStub instead of the real repository:

Java
TestCrudRepositoryStub repository = new TestCrudRepositoryStub();
TestService testService = new TestService(repository);
Kotlin
val repository = TestCrudRepositoryStub()
val testService = TestService(repository)

Now we can prepare our test scenario by simply adding entities to the stub. Either one-by-one:

Java
TestEntity savedEntity = repository.save(new TestEntity(randomUUID(), "first entity"));
Kotlin
val savedEntity = repository.save(TestEntity(randomUUID(), "first entity"))

Or multiple at once:

Java
Iterable<TestEntity> savedEntities =
    repository.saveAll(
        List.of(
            new TestEntity(randomUUID(), "second entity"),
            new TestEntity(randomUUID(), "third entity")));
Kotlin
val savedEntities =
    repository.saveAll(
        listOf(
            TestEntity(randomUUID(), "second entity"),
            TestEntity(randomUUID(), "third entity")))

It is quite handy, that the save methods of a CrudRepository return the saved entity, so we can easily add the entity to the stub and use the returned entity in our test.

Verify the Stub

After the test, we can verify the stub by checking the entities in the stub:

Java
assertThat(testService.getAll()).contains(savedEntity).containsAll(savedEntities);
assertThat(repository.findByName("first entity")).isPresent().contains(savedEntity);
Kotlin
assertThat(testService.getAll()).contains(savedEntity).containsAll(savedEntities)
assertThat(repository.findByName("first entity")).isNotNull().isEqualTo(savedEntity)

Reusing a Stub

Note that a CrudRepositoryStub is basically a glorified HashMap, so we can simply create a new instance for every test.

However, that might require to recreate the service as well. So, if we want to reuse the stub, we can simply use the deleteAll method to clear the stub:

Java
repository.deleteAll();
Kotlin
repository.deleteAll()

Random

The Random module contains a collection of builders and utility functions to generate random data.

Random Number

The RandomNumber class allows to generate random Integer/Long values within a defined min and max range (both inclusive).

For simple integers/longs there are several static methods available. More complex integers/long can be defined with Builder classes that’s returned by the anInt/aLong methods.

NOTE

It is not possible to set max to Integer.MAX_VALUE or Long.MAX_VALUE. The maximum values are Integer.MAX_VALUE - 1 and Long.MAX_VALUE - 1. This is due to the fact that the SecureRandom.nextInt(int) and SecureRandom.nextLong(long) methods are exclusive of the upper bound.

Between Min and Max

Java
int someIntBetween42And4711 = anIntBetween(42, 4711);
assertThat(someIntBetween42And4711).isBetween(42, 4711);

long someLongBetween42And4711 = aLongBetween(42, 4711);
assertThat(someLongBetween42And4711).isBetween(42L, 4711L);
Kotlin
val someIntBetween42And4711 = anIntBetween(42, 4711)
assertThat(someIntBetween42And4711).isBetween(42, 4711)

val someLongBetween42And4711 = aLongBetween(42, 4711)
assertThat(someLongBetween42And4711).isBetween(42L, 4711L)

Positive Integer/Long

Java
int somePositiveInt = aPositiveInt();
assertThat(somePositiveInt).isPositive().isNotZero().isLessThan(Integer.MAX_VALUE);
Kotlin
val somePositiveInt = aPositiveInt()
assertThat(somePositiveInt).isPositive().isNotZero().isLessThan(Integer.MAX_VALUE)
Java
long somePositiveLong = aPositiveLong();
assertThat(somePositiveLong).isPositive().isNotZero().isLessThan(Long.MAX_VALUE);
Kotlin
val somePositiveLong = aPositiveLong()
assertThat(somePositiveLong).isPositive().isNotZero().isLessThan(Long.MAX_VALUE)

Negative Integer/Long

Java
int someNegativeInt = aNegativeInt();
assertThat(someNegativeInt).isNegative().isNotZero().isGreaterThanOrEqualTo(Integer.MIN_VALUE);
Kotlin
val someNegativeInt = aNegativeInt()
assertThat(someNegativeInt).isNegative().isNotZero().isGreaterThanOrEqualTo(Integer.MIN_VALUE)
Java
long someNegativeLong = aNegativeLong();
assertThat(someNegativeLong).isNegative().isNotZero().isGreaterThanOrEqualTo(Long.MIN_VALUE);
Kotlin
val someNegativeLong = aNegativeLong()
assertThat(someNegativeLong).isNegative().isNotZero().isGreaterThanOrEqualTo(Long.MIN_VALUE)

Builder

Java
int someInt = anInt().build();
assertThat(someInt).isBetween(Integer.MIN_VALUE, Integer.MAX_VALUE - 1);

int someIntBetween42And4711 = anInt().min(42).max(4711).build();
assertThat(someIntBetween42And4711).isBetween(42, 4711);

int someIntLessThan4711 = anInt().max(4711).build();
assertThat(someIntLessThan4711).isLessThanOrEqualTo(4711);

int someIntGreaterThanMinus10 = anInt().min(-42).build();
assertThat(someIntGreaterThanMinus10).isGreaterThanOrEqualTo(-42);
Kotlin
val someInt = anInt().build()
assertThat(someInt).isBetween(Integer.MIN_VALUE, Integer.MAX_VALUE - 1)

val someIntBetween42And4711 = anInt().min(42).max(4711).build()
assertThat(someIntBetween42And4711).isBetween(42, 4711)

val someIntLessThan4711 = anInt().max(4711).build()
assertThat(someIntLessThan4711).isLessThanOrEqualTo(4711)

val someIntGreaterThanMinus10 = anInt().min(-42).build()
assertThat(someIntGreaterThanMinus10).isGreaterThanOrEqualTo(-42)
Java
long someLong = aLong().build();
assertThat(someLong).isBetween(Long.MIN_VALUE, Long.MAX_VALUE - 1);

long someLongBetween42And4711 = aLong().min(42L).max(4711L).build();
assertThat(someLongBetween42And4711).isBetween(42L, 4711L);

long someLongLessThan4711 = aLong().max(4711L).build();
assertThat(someLongLessThan4711).isLessThanOrEqualTo(4711L);

long someLongGreaterThanMinus10 = aLong().min(-42L).build();
assertThat(someLongGreaterThanMinus10).isGreaterThanOrEqualTo(-42L);
Kotlin
val someLong = aLong().build()
assertThat(someLong).isBetween(Long.MIN_VALUE, Long.MAX_VALUE - 1)

val someLongBetween42And4711 = aLong().min(42L).max(4711L).build()
assertThat(someLongBetween42And4711).isBetween(42L, 4711L)

val someLongLessThan4711 = aLong().max(4711L).build()
assertThat(someLongLessThan4711).isLessThanOrEqualTo(4711L)

val someLongGreaterThanMinus10 = aLong().min(-42L).build()
assertThat(someLongGreaterThanMinus10).isGreaterThanOrEqualTo(-42L)

Random Choice

The RandomChoice class allows to make a random choice from the objects in a Collection, an Array, or the values of an Enum type.

For simple selections there are several static chooseAnyFrom methods available. More complex selections can be defined with a Builder class that’s returned by the from method.

From Collection

Java
List<String> choicesList = List.of("a", "b", "c");
String choiceFromList = anyOf(choicesList);
assertThat(choiceFromList).isIn(choicesList);

Map<String, Integer> choicesMap = Map.of("a", 1, "b", 2, "c", 3);
Map.Entry<String, Integer> choiceFromMap = anyOf(choicesMap);
assertThat(choiceFromMap).isIn(choicesMap.entrySet());
Kotlin
val choicesList = List.of("a", "b", "c")
val choiceFromList = anyOf(choicesList)
assertThat(choiceFromList).isIn(choicesList)

val choicesMap = mapOf("a" to 1, "b" to 2, "c" to 3)
val choiceFromMap = anyOf(choicesMap)
assertThat(choiceFromMap).isIn(choicesMap.entries)

From Array

Java
String choiceFromEllipsis = anyOf("a", "b", "c");
assertThat(choiceFromEllipsis).isIn("a", "b", "c");

String[] choiceArray = {"a", "b", "c"};
String choiceFromArray = anyOf(choiceArray[0], choiceArray[1], choiceArray[2]);
assertThat(choiceFromArray).isIn((Object[]) choiceArray);
Kotlin
val choiceFromEllipsis = anyOf("a", "b", "c")
assertThat(choiceFromEllipsis).isIn("a", "b", "c")

val choiceArray = arrayOf("a", "b", "c")
val choiceFromArray = anyOf(choiceArray)
assertThat(choiceFromArray).isIn(choiceArray)

From Enum Type

Java
enum Color {
  RED,
  GREEN,
  BLUE
}
Color choiceFromEnum = any(Color.class);
assertThat(choiceFromEnum).isIn(Color.RED, Color.GREEN, Color.BLUE);
Kotlin
val choiceFromEnum = any(Color::class.java)
assertThat(choiceFromEnum).isIn(Color.RED, Color.GREEN, Color.BLUE)

Builder

Java
String choiceFromEllipsis = aChoiceFrom("a", "b", "c").build();
assertThat(choiceFromEllipsis).isIn("a", "b", "c");

String[] choicesArray = {"a", "b", "c"};
String choiceFromArray = aChoiceFrom(choicesArray).build();
assertThat(choiceFromArray).isIn((Object[]) choicesArray);

var choicesList = List.of("a", "b", "c");
String choiceFromList = aChoiceFrom(choicesList).build();
assertThat(choiceFromList).isIn(choicesList);
Map<String, Integer> choicesMap = Map.of("a", 1, "b", 2, "c", 3);
Map.Entry<String, Integer> choiceFromMap = aChoiceFrom(choicesMap).build();
assertThat(choiceFromMap).isIn(choicesMap.entrySet());

enum Color {
  RED,
  GREEN,
  BLUE
}
Color choiceFromEnum = aChoiceFromValuesOf(Color.class).build();
assertThat(choiceFromEnum).isIn(Color.RED, Color.GREEN, Color.BLUE);
Kotlin
val choiceFromEllipsis = aChoiceFrom("a", "b", "c").build()
assertThat(choiceFromEllipsis).isIn("a", "b", "c")

val choicesArray = arrayOf("a", "b", "c")
val choiceFromArray = aChoiceFrom(choicesArray).build()
assertThat(choiceFromArray).isIn(choicesArray)

val choicesList = listOf("a", "b", "c")
val choiceFromList = aChoiceFrom(choicesList).build()
assertThat(choiceFromList).isIn(choicesList)
val choicesMap = mapOf("a" to 1, "b" to 2, "c" to 3)
val choiceFromMap = aChoiceFrom(choicesMap).build()
assertThat(choiceFromMap).isIn(choicesMap.entries)

val choiceFromEnum = aChoiceFromValuesOf(Color::class.java).build()
assertThat(choiceFromEnum).isIn(Color.RED, Color.GREEN, Color.BLUE)
Additional Choices
Java
String choiceWithAdditions = aChoiceFrom(List.of("a", "b")).and("c", "d").build();
assertThat(choiceWithAdditions).isIn("a", "b", "c", "d");
Kotlin
val choiceWithAdditions = aChoiceFrom("a", "b").and("c", "d").build()
assertThat(choiceWithAdditions).isIn("a", "b", "c", "d")
Excluding Choices
Java
String choiceWithExclusions = aChoiceFrom(List.of("a", "b", "c")).butNot("a").build();
assertThat(choiceWithExclusions).isNotEqualTo("a");
Kotlin
val choiceWithExclusions = aChoiceFrom("a", "b", "c").butNot("a").build()
assertThat(choiceWithExclusions).isNotEqualTo("a")

Random String

The RandomString class allows to generate random Strings.

E.g. to generate a random German licence plate:

Java
String germanLicensePlate =
    aStringStartingWith(lettersFrom(anIntBetween(1, 3), Alphabet.GERMAN).toUpperCase())
        .followedBy("-")
        .followedBy(latinLetters(2).toUpperCase())
        .followedBy(arabicDigits(anIntBetween(1, 4)))
        .build();

assertThat(germanLicensePlate).matches("[A-ZÄÖÜẞ]{1,3}-[A-Z]{2}\\d{1,4}");
Kotlin
val germanLicensePlate =
    aStringStartingWith(lettersFrom(anIntBetween(1, 3), Alphabet.GERMAN).uppercase())
        .followedBy("-")
        .followedBy(latinLetters(2).uppercase())
        .followedBy(arabicDigits(anIntBetween(1, 4)))
        .build()

assertThat(germanLicensePlate).matches("[A-ZÄÖÜẞ]{1,3}-[A-Z]{2}\\d{1,4}")

Or an Iranian licence plate:

Java
String iranianLicensePlate =
    aStringStartingWith(digitsFrom(2, DigitSystem.PERSIAN))
        .followedBy(aLetterFrom(Alphabet.BASIC_ARABIC))
        .followedBy(digitsFrom(3, DigitSystem.PERSIAN))
        .build();

assertThat(iranianLicensePlate).matches("[۰-۹]{2}[\\u0600-\\u06FF][۰-۹]{3}");
Kotlin
val iranianLicensePlate =
    aStringStartingWith(digitsFrom(2, DigitSystem.PERSIAN))
        .followedBy(aLetterFrom(Alphabet.BASIC_ARABIC))
        .followedBy(digitsFrom(3, DigitSystem.PERSIAN))
        .build()

assertThat(iranianLicensePlate).matches("[۰-۹]{2}[\\u0600-\\u06FF][۰-۹]{3}")

Random Duration

The RandomDuration class allows to generate random Durations.

Java
Duration someDuration = aDurationBetween(Duration.ZERO, Duration.ofDays(7));
assertThat(someDuration).isBetween(Duration.ZERO, Duration.ofDays(7));
Kotlin
val someDuration = aDurationBetween(Duration.ZERO, Duration.ofDays(7))
assertThat(someDuration).isBetween(Duration.ZERO, Duration.ofDays(7))
Java
Duration someDuration = aDuration().build();
assertThat(someDuration).isBetween(Duration.ZERO, Duration.ofSeconds(Long.MAX_VALUE - 1));

Duration someDurationBetween1And2Hours =
    aDuration().min(Duration.ofHours(1)).max(Duration.ofHours(2)).build();
assertThat(someDurationBetween1And2Hours).isBetween(Duration.ofHours(1), Duration.ofHours(2));

Duration someDurationLessThan2Hours = aDuration().max(Duration.ofHours(2)).build();
assertThat(someDurationLessThan2Hours).isLessThanOrEqualTo(Duration.ofHours(2));

Duration someDurationGreaterThan1Hour = aDuration().min(Duration.ofHours(1)).build();
assertThat(someDurationGreaterThan1Hour).isGreaterThanOrEqualTo(Duration.ofHours(1));
Kotlin
val someDuration = aDuration().build()
assertThat(someDuration).isBetween(Duration.ZERO, Duration.ofSeconds(Long.MAX_VALUE - 1))

val someDurationBetween1And2Hours =
    aDuration().min(Duration.ofHours(1)).max(Duration.ofHours(2)).build()
assertThat(someDurationBetween1And2Hours).isBetween(Duration.ofHours(1), Duration.ofHours(2))

val someDurationLessThan2Hours = aDuration().max(Duration.ofHours(2)).build()
assertThat(someDurationLessThan2Hours).isLessThanOrEqualTo(Duration.ofHours(2))

val someDurationGreaterThan1Hour = aDuration().min(Duration.ofHours(1)).build()
assertThat(someDurationGreaterThan1Hour).isGreaterThanOrEqualTo(Duration.ofHours(1))

Random Date

The RandomLocalDate class allows to generate random LocalDates.

Java
LocalDate someLockdownDay =
    aLocalDateBetween(LocalDate.of(2020, 3, 8), LocalDate.of(2020, 5, 4));
assertThat(someLockdownDay).isBetween(LocalDate.of(2020, 3, 8), LocalDate.of(2020, 5, 4));
Kotlin
val someLockdownDay =
    aLocalDateBetween(LocalDate.of(2020, 3, 8), LocalDate.of(2020, 5, 4))
assertThat(someLockdownDay).isBetween(LocalDate.of(2020, 3, 8), LocalDate.of(2020, 5, 4))
Java
LocalDate someLocalDate = aLocalDate().build();
assertThat(someLocalDate).isBetween(LocalDate.MIN, LocalDate.MAX);

LocalDate someDateIn2025 = aLocalDate().year(2025).build();
assertThat(someDateIn2025.getYear()).isEqualTo(2025);

LocalDate someDateInMarch = aLocalDate().month(Month.MARCH).build();
assertThat(someDateInMarch.getMonth()).isEqualTo(Month.MARCH);

LocalDate someDateInMarch2025 = aLocalDate().year(2025).month(Month.MARCH).build();
assertThat(someDateInMarch2025.getYear()).isEqualTo(2025);
assertThat(someDateInMarch2025.getMonth()).isEqualTo(Month.MARCH);

LocalDate some3rd = aLocalDate().dayOfMonth(3).build();
assertThat(some3rd.getDayOfMonth()).isEqualTo(3);

LocalDate someSunday = aLocalDate().dayOfWeek(DayOfWeek.SUNDAY).build();
assertThat(someSunday.getDayOfWeek()).isEqualTo(DayOfWeek.SUNDAY);

LocalDate someTuesday1999 = aLocalDate().year(1999).dayOfWeek(DayOfWeek.TUESDAY).build();
assertThat(someTuesday1999.getDayOfWeek()).isEqualTo(DayOfWeek.TUESDAY);
assertThat(someTuesday1999.getYear()).isEqualTo(1999);
Kotlin
val someLocalDate = aLocalDate().build()
assertThat(someLocalDate).isBetween(LocalDate.MIN, LocalDate.MAX)

val someDateIn2025 = aLocalDate().year(2025).build()
assertThat(someDateIn2025.year).isEqualTo(2025)

val someDateInMarch = aLocalDate().month(Month.MARCH).build()
assertThat(someDateInMarch.month).isEqualTo(Month.MARCH)

val someDateInMarch2025 = aLocalDate().year(2025).month(Month.MARCH).build()
assertThat(someDateInMarch2025.year).isEqualTo(2025)
assertThat(someDateInMarch2025.month).isEqualTo(Month.MARCH)

val some3rd = aLocalDate().dayOfMonth(3).build()
assertThat(some3rd.dayOfMonth).isEqualTo(3)

val someSunday = aLocalDate().dayOfWeek(DayOfWeek.SUNDAY).build()
assertThat(someSunday.dayOfWeek).isEqualTo(DayOfWeek.SUNDAY)

val someTuesday1999 = aLocalDate().year(1999).dayOfWeek(DayOfWeek.TUESDAY).build()
assertThat(someTuesday1999.dayOfWeek).isEqualTo(DayOfWeek.TUESDAY)
assertThat(someTuesday1999.year).isEqualTo(1999)
Java
LocalDate someLocalDate = aLocalDateInRange().build();
assertThat(someLocalDate).isBetween(LocalDate.MIN, LocalDate.MAX);

LocalDate someFutureDay = aLocalDateInRange().future().build();
assertThat(someFutureDay).isAfterOrEqualTo(LocalDate.now());

LocalDate somePastDay = aLocalDateInRange().past().build();
assertThat(somePastDay).isBeforeOrEqualTo(LocalDate.now());

LocalDate somePastAfterChristDay =
    aLocalDateInRange().past().after(LocalDate.of(1, 1, 1)).build();
assertThat(somePastAfterChristDay)
    .isBeforeOrEqualTo(LocalDate.now())
    .isAfterOrEqualTo(LocalDate.of(1, 1, 1));

LocalDate someFutureDayInTheNext5Years =
    aLocalDateInRange().future().before(Year.now().plusYears(5).atDay(1)).build();
assertThat(someFutureDayInTheNext5Years)
    .isAfterOrEqualTo(LocalDate.now())
    .isBeforeOrEqualTo(Year.now().plusYears(5).atDay(1));

LocalDate someLockdownDay =
    aLocalDateInRange()
        .after(LocalDate.of(2020, 3, 8))
        .before(LocalDate.of(2020, 5, 4))
        .build();
assertThat(someLockdownDay).isBetween(LocalDate.of(2020, 3, 8), LocalDate.of(2020, 5, 4));
Kotlin
val someLocalDate = aLocalDateInRange().build()
assertThat(someLocalDate).isBetween(LocalDate.MIN, LocalDate.MAX)

val someFutureDay = aLocalDateInRange().future().build()
assertThat(someFutureDay).isAfterOrEqualTo(LocalDate.now())

val somePastDay = aLocalDateInRange().past().build()
assertThat(somePastDay).isBeforeOrEqualTo(LocalDate.now())

val somePastAfterChristDay =
    aLocalDateInRange().past().after(LocalDate.of(1, 1, 1)).build()
assertThat(somePastAfterChristDay)
    .isBeforeOrEqualTo(LocalDate.now())
    .isAfterOrEqualTo(LocalDate.of(1, 1, 1))

val someFutureDayInTheNext5Years =
    aLocalDateInRange().future().before(Year.now().plusYears(5).atDay(1)).build()
assertThat(someFutureDayInTheNext5Years)
    .isAfterOrEqualTo(LocalDate.now())
    .isBeforeOrEqualTo(Year.now().plusYears(5).atDay(1))

val someLockdownDay =
    aLocalDateInRange()
        .after(LocalDate.of(2020, 3, 8))
        .before(LocalDate.of(2020, 5, 4))
        .build()
assertThat(someLockdownDay).isBetween(LocalDate.of(2020, 3, 8), LocalDate.of(2020, 5, 4))

Random Time

The RandomLocalTime class allows to generate random LocalTimes.

Java
LocalTime someTimeBusinessHours = aLocalTimeBetween(LocalTime.of(9, 0), LocalTime.of(17, 0, 0));
assertThat(someTimeBusinessHours).isBetween(LocalTime.of(9, 0), LocalTime.of(17, 0));
Kotlin
val someTimeBusinessHours = aLocalTimeBetween(LocalTime.of(9, 0), LocalTime.of(17, 0, 0))
assertThat(someTimeBusinessHours).isBetween(LocalTime.of(9, 0), LocalTime.of(17, 0))
Java
LocalTime someLocalTime = aLocalTime().build();
assertThat(someLocalTime).isBetween(LocalTime.MIN, LocalTime.MAX);

LocalTime someTimeAt12 = aLocalTime().hour(12).build();
assertThat(someTimeAt12.getHour()).isEqualTo(12);

LocalTime someHalfTime = aLocalTime().minute(30).build();
assertThat(someHalfTime.getMinute()).isEqualTo(30);

LocalTime someTimeAlmostFull = aLocalTime().minute(59).second(59).nano(999_999_999).build();
assertThat(someTimeAlmostFull.getMinute()).isEqualTo(59);
assertThat(someTimeAlmostFull.getSecond()).isEqualTo(59);
assertThat(someTimeAlmostFull.getNano()).isEqualTo(999_999_999);
Kotlin
val someLocalTime = aLocalTime().build()
assertThat(someLocalTime).isBetween(LocalTime.MIN, LocalTime.MAX)

val someTimeAt12 = aLocalTime().hour(12).build()
assertThat(someTimeAt12.hour).isEqualTo(12)

val someHalfTime = aLocalTime().minute(30).build()
assertThat(someHalfTime.minute).isEqualTo(30)

val someTimeAlmostFull = aLocalTime().minute(59).second(59).nano(999_999_999).build()
assertThat(someTimeAlmostFull.minute).isEqualTo(59)
assertThat(someTimeAlmostFull.second).isEqualTo(59)
assertThat(someTimeAlmostFull.nano).isEqualTo(999_999_999)
Java
LocalTime someLocalTime = aLocalTimeInRange().build();
assertThat(someLocalTime).isBetween(LocalTime.MIN, LocalTime.MAX);

LocalTime someFutureTime = aLocalTimeInRange().future().build();
assertThat(someFutureTime).isAfterOrEqualTo(LocalTime.now());

LocalTime somePastTime = aLocalTimeInRange().past().build();
assertThat(somePastTime).isBeforeOrEqualTo(LocalTime.now());

LocalTime someTimeAfterNoon = aLocalTimeInRange().after(LocalTime.NOON).build();
assertThat(someTimeAfterNoon).isAfterOrEqualTo(LocalTime.NOON);
Kotlin
val someLocalTime = aLocalTimeInRange().build()
assertThat(someLocalTime).isBetween(LocalTime.MIN, LocalTime.MAX)

val someFutureTime = aLocalTimeInRange().future().build()
assertThat(someFutureTime).isAfterOrEqualTo(LocalTime.now())

val somePastTime = aLocalTimeInRange().past().build()
assertThat(somePastTime).isBeforeOrEqualTo(LocalTime.now())

val someTimeAfterNoon = aLocalTimeInRange().after(LocalTime.NOON).build()
assertThat(someTimeAfterNoon).isAfterOrEqualTo(LocalTime.NOON)