Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sr junit5 functional interfaces #309

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ then
build_gradle_module "spring-data/spring-data-jdbc-converter"
build_gradle_module "reactive"
build_gradle_module "junit/assumptions"
build_maven_module "junit/junit5/junit5"
build_maven_module "junit/junit5/functional-interfaces"
build_gradle_module "logging"
build_gradle_module "pact/pact-feign-consumer"

Expand Down
35 changes: 35 additions & 0 deletions junit/junit5/functional-interfaces/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

.vscode

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/
41 changes: 41 additions & 0 deletions junit/junit5/functional-interfaces/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>io.reflectoring</groupId>
<artifactId>junit5-functional-interfaces</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<junit.version>5.9.0</junit.version>
</properties>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.reflectoring.functional;

public class ValidationException extends Throwable {
public ValidationException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package io.reflectoring.functional;

import static org.junit.jupiter.api.Assertions.*;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.opentest4j.AssertionFailedError;

public class ExecutableTest {
private final List<Long> numbers = Arrays.asList(100L, 200L, 50L, 300L);
final Executable sorter =
() -> {
TimeUnit.SECONDS.sleep(2);
numbers.sort(Long::compareTo);
};
private final Executable checkSorting =
() -> assertEquals(List.of(50L, 100L, 200L, 300L), numbers);
private final Executable noChanges = () -> assertEquals(List.of(100L, 200L, 50L, 300L), numbers);

@ParameterizedTest
@CsvSource({"1,1,2,Hello,H,bye,2,byebye", "4,5,9,Good,Go,Go,-10,", "10,21,31,Team,Tea,Stop,-2,"})
void testAssertAllWithExecutable(
int num1,
int num2,
int sum,
String input,
String prefix,
String arg,
int count,
String result) {
assertAll(
() -> assertEquals(sum, num1 + num2),
() -> assertTrue(input.startsWith(prefix)),
() -> {
if (count < 0) {
assertThrows(
IllegalArgumentException.class,
() -> {
new ArrayList<>(count);
});
} else {
assertEquals(result, arg.repeat(count));
}
});
}

@ParameterizedTest
@CsvSource({"one,0,o", "one,1,n"})
void testAssertDoesNotThrowWithExecutable(String input, int index, char result) {
assertDoesNotThrow(() -> assertEquals(input.charAt(index), result));
}

@Test
void testAssertThrowsWithExecutable() {
List<String> input = Arrays.asList("one", "", "three", null, "five");
final IllegalArgumentException exception =
assertThrows(
IllegalArgumentException.class,
() -> {
for (String value : input) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException("Got invalid value");
}
// process values
}
});
assertEquals("Got invalid value", exception.getMessage());
}

@Test
void testAssertTimeoutWithExecutable() {
assertAll(
() ->
assertThrows(
AssertionFailedError.class, () -> assertTimeout(Duration.ofSeconds(1), sorter)),
checkSorting);

assertAll(
() -> assertDoesNotThrow(() -> assertTimeout(Duration.ofSeconds(5), sorter)), checkSorting);
}

@Test
void testAssertTimeoutPreemptivelyWithExecutable() {
assertAll(
() ->
assertThrows(
AssertionFailedError.class,
() -> assertTimeoutPreemptively(Duration.ofSeconds(1), sorter)),
noChanges);

assertAll(
() -> assertDoesNotThrow(() -> assertTimeoutPreemptively(Duration.ofSeconds(5), sorter)),
checkSorting);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package io.reflectoring.functional;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.text.MessageFormat;
import java.time.temporal.ValueRange;
import java.util.Arrays;
import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Stream;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.ThrowingConsumer;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

public class ThrowingConsumerTest {
@ParameterizedTest
@CsvSource({"50,true", "130,false", "-30,false"})
void testMethodThatThrowsCheckedException(int percent, boolean valid) {
// acceptable percentage range: 0 - 100
ValueRange validPercentageRange = ValueRange.of(0, 100);
final Function<Integer, String> message =
input ->
MessageFormat.format(
"Percentage {0} should be in range {1}", input, validPercentageRange.toString());

ThrowingConsumer<Integer> consumer =
input -> {
if (!validPercentageRange.isValidValue(input)) {
throw new ValidationException(message.apply(input));
}
};

if (valid) {
assertDoesNotThrow(() -> consumer.accept(percent));
} else {
assertAll(
() -> {
ValidationException exception =
assertThrows(ValidationException.class, () -> consumer.accept(percent));
assertEquals(exception.getMessage(), message.apply(percent));
});
}
}

@TestFactory
Stream<DynamicTest> testDynamicTestsWithThrowingConsumer() {
// acceptable percentage range: 0 - 100
ValueRange validPercentageRange = ValueRange.of(0, 100);
final Function<Integer, String> message =
input ->
MessageFormat.format(
"Percentage {0} should be in range {1}", input, validPercentageRange.toString());

// Define the ThrowingConsumer that validates the input percentage
ThrowingConsumer<TestCase> consumer =
testCase -> {
if (!validPercentageRange.isValidValue(testCase.percent)) {
throw new ValidationException(message.apply(testCase.percent));
}
};

ThrowingConsumer<TestCase> executable =
testCase -> {
if (testCase.valid) {
assertDoesNotThrow(() -> consumer.accept(testCase));
} else {
assertAll(
() -> {
ValidationException exception =
assertThrows(ValidationException.class, () -> consumer.accept(testCase));
assertEquals(exception.getMessage(), message.apply(testCase.percent));
});
}
};
// Test data: an array of test cases with inputs and their validity
Collection<TestCase> testCases =
Arrays.asList(new TestCase(50, true), new TestCase(130, false), new TestCase(-30, false));

Function<TestCase, String> displayNameGenerator =
testCase -> "Testing percentage: " + testCase.percent;

// Generate dynamic tests
return DynamicTest.stream(testCases.stream(), displayNameGenerator, executable);
}

// Helper record to represent a test case
record TestCase(int percent, boolean valid) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package io.reflectoring.functional;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTimeout;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.ThrowingSupplier;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.opentest4j.AssertionFailedError;

public class ThrowingSupplierTest {
private final List<Long> numbers = Arrays.asList(100L, 200L, 50L, 300L);
private final Consumer<List<Long>> checkSorting =
list -> assertEquals(List.of(50L, 100L, 200L, 300L), list);

ThrowingSupplier<List<Long>> sorter =
() -> {
if (numbers == null || numbers.isEmpty() || numbers.contains(null)) {
throw new ValidationException("Invalid input");
}
TimeUnit.SECONDS.sleep(2);
return numbers.stream().sorted().toList();
};

@ParameterizedTest
@CsvSource({"25.0d,5.0d", "36.0d,6.0d", "49.0d,7.0d"})
void testDoesNotThrowWithSupplier(double input, double expected) {
ThrowingSupplier<Double> findSquareRoot =
() -> {
if (input < 0) {
throw new ValidationException("Invalid input");
}
return Math.sqrt(input);
};
assertEquals(expected, assertDoesNotThrow(findSquareRoot));
}

@Test
void testAssertTimeoutWithSupplier() {
// slow execution
assertThrows(AssertionFailedError.class, () -> assertTimeout(Duration.ofSeconds(1), sorter));

// fast execution
assertDoesNotThrow(
() -> {
List<Long> result = assertTimeout(Duration.ofSeconds(5), sorter);
checkSorting.accept(result);
});

// reset the number list and verify if the supplier validates it
Collections.fill(numbers, null);

ValidationException exception =
assertThrows(ValidationException.class, () -> assertTimeout(Duration.ofSeconds(1), sorter));
assertEquals("Invalid input", exception.getMessage());
}

@Test
void testAssertTimeoutPreemptivelyWithSupplier() {
// slow execution
assertThrows(
AssertionFailedError.class, () -> assertTimeoutPreemptively(Duration.ofSeconds(1), sorter));

// fast execution
assertDoesNotThrow(
() -> {
List<Long> result = assertTimeoutPreemptively(Duration.ofSeconds(5), sorter);
checkSorting.accept(result);
});
}
}
Loading