From 146b633bacef437ea51c1d9ed0bc3526b53505b3 Mon Sep 17 00:00:00 2001 From: Makoto Go Date: Thu, 10 Aug 2017 08:27:27 -0500 Subject: [PATCH] New artifacts for BAEL-1081. (#2392) * New artifacts for BAEL-1081. * Consolidate code to new package. --- junit5/pom.xml | 8 +- .../param/InvalidPersonParameterResolver.java | 50 ++++++ .../test/java/com/baeldung/param/Person.java | 43 ++++++ .../com/baeldung/param/PersonValidator.java | 142 ++++++++++++++++++ .../baeldung/param/PersonValidatorTest.java | 102 +++++++++++++ .../param/ValidPersonParameterResolver.java | 50 ++++++ 6 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 junit5/src/test/java/com/baeldung/param/InvalidPersonParameterResolver.java create mode 100644 junit5/src/test/java/com/baeldung/param/Person.java create mode 100644 junit5/src/test/java/com/baeldung/param/PersonValidator.java create mode 100644 junit5/src/test/java/com/baeldung/param/PersonValidatorTest.java create mode 100644 junit5/src/test/java/com/baeldung/param/ValidPersonParameterResolver.java diff --git a/junit5/pom.xml b/junit5/pom.xml index 2316b034e9..1fa4818447 100644 --- a/junit5/pom.xml +++ b/junit5/pom.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung + junit5 1.0-SNAPSHOT @@ -19,9 +19,9 @@ UTF-8 1.8 - 5.0.0-M5 - 1.0.0-M5 - 4.12.0-M5 + 5.0.0-RC2 + 1.0.0-RC2 + 4.12.0-RC2 2.8.2 1.4.196 diff --git a/junit5/src/test/java/com/baeldung/param/InvalidPersonParameterResolver.java b/junit5/src/test/java/com/baeldung/param/InvalidPersonParameterResolver.java new file mode 100644 index 0000000000..67bd47a44a --- /dev/null +++ b/junit5/src/test/java/com/baeldung/param/InvalidPersonParameterResolver.java @@ -0,0 +1,50 @@ +package com.baeldung.param; + +import java.util.Random; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +public class InvalidPersonParameterResolver implements ParameterResolver { + + /** + * The "bad" (invalid) data for testing purposes has to go somewhere, right? + */ + public static Person[] INVALID_PERSONS = { + new Person().setId(1L).setLastName("Ad_ams").setFirstName("Jill,"), + new Person().setId(2L).setLastName(",Baker").setFirstName(""), + new Person().setId(3L).setLastName(null).setFirstName(null), + new Person().setId(4L).setLastName("Daniel&").setFirstName("{Joseph}"), + new Person().setId(5L).setLastName("").setFirstName("English, Jane"), + new Person()/* .setId(6L).setLastName("Fontana").setFirstName("Enrique") */, + // TODO: ADD MORE DATA HERE + }; + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + Object ret = null; + // + // Return a random, valid Person object if Person.class is the type of Parameter + /// to be resolved. Otherwise return null. + if (parameterContext.getParameter().getType() == Person.class) { + ret = INVALID_PERSONS[new Random().nextInt(INVALID_PERSONS.length)]; + } + return ret; + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + boolean ret = false; + // + // If the Parameter.type == Person.class, then we support it, otherwise, get outta here! + if (parameterContext.getParameter().getType() == Person.class) { + ret = true; + } + return ret; + } + +} diff --git a/junit5/src/test/java/com/baeldung/param/Person.java b/junit5/src/test/java/com/baeldung/param/Person.java new file mode 100644 index 0000000000..65333b5e56 --- /dev/null +++ b/junit5/src/test/java/com/baeldung/param/Person.java @@ -0,0 +1,43 @@ +package com.baeldung.param; + +/** + * Very simple Person entity. + * Use the Fluent-style interface to set properties. + * + * @author J Steven Perry + * + */ +public class Person { + + private Long id; + private String lastName; + private String firstName; + + public Long getId() { + return id; + } + + public Person setId(Long id) { + this.id = id; + return this; + } + + public String getLastName() { + return lastName; + } + + public Person setLastName(String lastName) { + this.lastName = lastName; + return this; + } + + public String getFirstName() { + return firstName; + } + + public Person setFirstName(String firstName) { + this.firstName = firstName; + return this; + } + +} diff --git a/junit5/src/test/java/com/baeldung/param/PersonValidator.java b/junit5/src/test/java/com/baeldung/param/PersonValidator.java new file mode 100644 index 0000000000..0219169aab --- /dev/null +++ b/junit5/src/test/java/com/baeldung/param/PersonValidator.java @@ -0,0 +1,142 @@ +package com.baeldung.param; + +import java.util.Arrays; + +/** + * Somewhat contrived validation class to illustrate unit test + * concepts. + * + * @author J Steven Perry + * + */ +public class PersonValidator { + + /** + * Contrived checked exception to illustrate one possible + * way to handle validation errors (via a checked exception). + * + * @author J Steven Perry + * + */ + public static class ValidationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -134518049431883102L; + + // Probably should implement some more constructors, but don't want + /// to tarnish the lesson... + + /** + * The one and only way to create this checked exception. + * + * @param message + * The message accompanying the exception. Should be meaningful. + */ + public ValidationException(String message) { + super(message); + + } + + } + + private static final String[] ILLEGAL_NAME_CHARACTERS = { + ",", + "_", + "{", + "}", + "!" + }; + + /** + * Validate the first name of the specified Person object. + * + * @param person + * The Person object to validate. + * + * @return - returns true if the specified Person is valid + * + * @throws ValidationException + * - this Exception is thrown if any kind of validation error occurs. + */ + public static boolean validateFirstName(Person person) throws ValidationException { + boolean ret = true; + // The validation rules go here. + // Naive: use simple ifs + if (person == null) { + throw new ValidationException("Person is null (not allowed)!"); + } + if (person.getFirstName() == null) { + throw new ValidationException("Person FirstName is null (not allowed)!"); + } + if (person.getFirstName().isEmpty()) { + throw new ValidationException("Person FirstName is an empty String (not allowed)!"); + } + if (!isStringValid(person.getFirstName(), ILLEGAL_NAME_CHARACTERS)) { + throw new ValidationException( + "Person FirstName (" + person.getFirstName() + ") may not contain any of the following characters: " + + Arrays.toString(ILLEGAL_NAME_CHARACTERS) + + "!"); + } + return ret; + } + + /** + * Validate the last name of the specified Person object. Looks the same as first + * name? Look closer. Just kidding. It's the same. But real world code can (and will) diverge. + * + * @param person + * The Person object to validate. + * + * @return - returns true if the specified Person is valid + * + * @throws ValidationException + * - this Exception is thrown if any kind of validation error occurs. + */ + public static boolean validateLastName(Person person) throws ValidationException { + boolean ret = true; + // The validation rules go here. + // Naive: use simple ifs + if (person == null) { + throw new ValidationException("Person is null (not allowed)!"); + } + if (person.getFirstName() == null) { + throw new ValidationException("Person FirstName is null (not allowed)!"); + } + if (person.getFirstName().isEmpty()) { + throw new ValidationException("Person FirstName is an empty String (not allowed)!"); + } + if (!isStringValid(person.getFirstName(), ILLEGAL_NAME_CHARACTERS)) { + throw new ValidationException( + "Person LastName (" + person.getLastName() + ") may not contain any of the following characters: " + + Arrays.toString(ILLEGAL_NAME_CHARACTERS) + + "!"); + } + return ret; + } + + /** + * Validates the specified name. If it contains any of the illegalCharacters, + * this method returns false (indicating the name is illegal). Otherwise it returns true. + * + * @param candidate + * The candidate String to validate + * + * @param illegalCharacters + * The characters the String is not allowed to have + * + * @return - boolean - true if the name is valid, false otherwise. + */ + private static boolean isStringValid(String candidate, String[] illegalCharacters) { + boolean ret = true; + for (String illegalChar : illegalCharacters) { + if (candidate.contains(illegalChar)) { + ret = false; + break; + } + } + return ret; + } + +} diff --git a/junit5/src/test/java/com/baeldung/param/PersonValidatorTest.java b/junit5/src/test/java/com/baeldung/param/PersonValidatorTest.java new file mode 100644 index 0000000000..09ab03b811 --- /dev/null +++ b/junit5/src/test/java/com/baeldung/param/PersonValidatorTest.java @@ -0,0 +1,102 @@ +package com.baeldung.param; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +@RunWith(JUnitPlatform.class) +@DisplayName("Testing PersonValidator") +public class PersonValidatorTest { + + /** + * Nested class, uses ExtendWith + * {@link com.baeldung.param.ValidPersonParameterResolver ValidPersonParameterResolver} + * to feed Test methods with "good" data. + */ + @Nested + @DisplayName("When using Valid data") + @ExtendWith(ValidPersonParameterResolver.class) + public class ValidData { + + /** + * Repeat the test ten times, that way we have a good shot at + * running all of the data through at least once. + * + * @param person + * A valid Person object to validate. + */ + @RepeatedTest(value = 10) + @DisplayName("All first names are valid") + public void validateFirstName(Person person) { + try { + assertTrue(PersonValidator.validateFirstName(person)); + } catch (PersonValidator.ValidationException e) { + fail("Exception not expected: " + e.getLocalizedMessage()); + } + } + + /** + * Repeat the test ten times, that way we have a good shot at + * running all of the data through at least once. + * + * @param person + * A valid Person object to validate. + */ + @RepeatedTest(value = 10) + @DisplayName("All last names are valid") + public void validateLastName(Person person) { + try { + assertTrue(PersonValidator.validateLastName(person)); + } catch (PersonValidator.ValidationException e) { + fail("Exception not expected: " + e.getLocalizedMessage()); + } + } + + } + + /** + * Nested class, uses ExtendWith + * {@link com.baeldung.param.InvalidPersonParameterResolver InvalidPersonParameterResolver} + * to feed Test methods with "bad" data. + */ + @Nested + @DisplayName("When using Invalid data") + @ExtendWith(InvalidPersonParameterResolver.class) + public class InvalidData { + + /** + * Repeat the test ten times, that way we have a good shot at + * running all of the data through at least once. + * + * @param person + * An invalid Person object to validate. + */ + @RepeatedTest(value = 10) + @DisplayName("All first names are invalid") + public void validateFirstName(Person person) { + assertThrows(PersonValidator.ValidationException.class, () -> PersonValidator.validateFirstName(person)); + } + + /** + * Repeat the test ten times, that way we have a good shot at + * running all of the data through at least once. + * + * @param person + * An invalid Person object to validate. + */ + @RepeatedTest(value = 10) + @DisplayName("All first names are invalid") + public void validateLastName(Person person) { + assertThrows(PersonValidator.ValidationException.class, () -> PersonValidator.validateLastName(person)); + } + + } + +} diff --git a/junit5/src/test/java/com/baeldung/param/ValidPersonParameterResolver.java b/junit5/src/test/java/com/baeldung/param/ValidPersonParameterResolver.java new file mode 100644 index 0000000000..abb97586eb --- /dev/null +++ b/junit5/src/test/java/com/baeldung/param/ValidPersonParameterResolver.java @@ -0,0 +1,50 @@ +package com.baeldung.param; + +import java.util.Random; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +public class ValidPersonParameterResolver implements ParameterResolver { + + /** + * The "good" (valid) data for testing purposes has to go somewhere, right? + */ + public static Person[] VALID_PERSONS = { + new Person().setId(1L).setLastName("Adams").setFirstName("Jill"), + new Person().setId(2L).setLastName("Baker").setFirstName("James"), + new Person().setId(3L).setLastName("Carter").setFirstName("Samanta"), + new Person().setId(4L).setLastName("Daniels").setFirstName("Joseph"), + new Person().setId(5L).setLastName("English").setFirstName("Jane"), + new Person().setId(6L).setLastName("Fontana").setFirstName("Enrique"), + // TODO: ADD MORE DATA HERE + }; + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + Object ret = null; + // + // Return a random, valid Person object if Person.class is the type of Parameter + /// to be resolved. Otherwise return null. + if (parameterContext.getParameter().getType() == Person.class) { + ret = VALID_PERSONS[new Random().nextInt(VALID_PERSONS.length)]; + } + return ret; + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + boolean ret = false; + // + // If the Parameter.type == Person.class, then we support it, otherwise, get outta here! + if (parameterContext.getParameter().getType() == Person.class) { + ret = true; + } + return ret; + } + +}