BAEL-3091: The Prototype Pattern in Java (changed code based on valid comments from a reader)

This commit is contained in:
Vivek Balasubramaniam
2019-10-29 22:27:15 +05:30
parent db85c8f275
commit d3d5b060e7
20517 changed files with 1642290 additions and 0 deletions
@@ -0,0 +1,6 @@
## Relevant Articles:
- [JUnit 5 TestWatcher API](https://www.baeldung.com/junit-testwatcher)
- [JUnit Custom Display Name Generator API](https://www.baeldung.com/junit-custom-display-name-generator)
- [@TestInstance Annotation in JUnit 5](https://www.baeldung.com/junit-testinstance-annotation)
+52
View File
@@ -0,0 +1,52 @@
<?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>
<artifactId>junit-5-advanced</artifactId>
<version>1.0-SNAPSHOT</version>
<name>junit-5-advanced</name>
<description>Advanced JUnit 5 Topics</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.vintage.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
</plugins>
</build>
<properties>
<junit-jupiter.version>5.4.2</junit-jupiter.version>
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
<junit.vintage.version>5.4.2</junit.vintage.version>
</properties>
</project>
@@ -0,0 +1,15 @@
package com.baeldung.failure_vs_error;
/**
* @author paullatzelsperger
* @since 2019-07-17
*/
public class SimpleCalculator {
public static double divideNumbers(double dividend, double divisor) {
if (divisor == 0) {
throw new ArithmeticException("Division by zero!");
}
return dividend / divisor;
}
}
@@ -0,0 +1,27 @@
package com.baeldung.junit5.testinstance;
import java.io.Serializable;
public class Tweet implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String content;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
@@ -0,0 +1,10 @@
package com.baeldung.junit5.testinstance;
public class TweetException extends RuntimeException {
private static final long serialVersionUID = 1L;
public TweetException(String message) {
super(message);
}
}
@@ -0,0 +1,41 @@
package com.baeldung.junit5.testinstance;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class TweetSerializer {
private static final int MAX_TWEET_SIZE = 1000;
private static final int MIN_TWEET_SIZE = 150;
private final Tweet tweet;
public TweetSerializer(Tweet tweet) {
this.tweet = tweet;
}
public byte[] serialize() throws IOException {
byte[] tweetContent = serializeTweet();
int totalLength = tweetContent.length;
validateSizeOfTweet(totalLength);
return tweetContent;
}
private void validateSizeOfTweet(int tweetSize) {
if (tweetSize > MAX_TWEET_SIZE) {
throw new TweetException("Tweet is too large");
}
if (tweetSize < MIN_TWEET_SIZE) {
throw new TweetException("Tweet is too small");
}
}
private byte[] serializeTweet() throws IOException {
try (ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectStream = new ObjectOutputStream(arrayOutputStream)) {
objectStream.writeObject(tweet);
return arrayOutputStream.toByteArray();
}
}
}
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,87 @@
package com.baeldung.displayname;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.lang.reflect.Method;
@DisplayNameGeneration(DisplayNameGeneratorUnitTest.ReplaceCamelCase.class)
class DisplayNameGeneratorUnitTest {
@Test
void camelCaseName() {
}
@Nested
@DisplayNameGeneration(DisplayNameGeneratorUnitTest.IndicativeSentences.class)
class ANumberIsFizz {
@Test
void ifItIsDivisibleByThree() {
}
@ParameterizedTest(name = "Number {0} is fizz.")
@ValueSource(ints = { 3, 12, 18 })
void ifItIsOneOfTheFollowingNumbers(int number) {
}
}
@Nested
@DisplayNameGeneration(DisplayNameGeneratorUnitTest.IndicativeSentences.class)
class ANumberIsBuzz {
@Test
void ifItIsDivisibleByFive() {
}
@ParameterizedTest(name = "Number {0} is buzz.")
@ValueSource(ints = { 5, 10, 20 })
void ifItIsOneOfTheFollowingNumbers(int number) {
}
}
static class IndicativeSentences extends ReplaceCamelCase {
@Override
public String generateDisplayNameForNestedClass(Class<?> nestedClass) {
return super.generateDisplayNameForNestedClass(nestedClass) + "...";
}
@Override
public String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {
return replaceCamelCase(testClass.getSimpleName() + " " + testMethod.getName()) + ".";
}
}
static class ReplaceCamelCase extends DisplayNameGenerator.Standard {
@Override
public String generateDisplayNameForClass(Class<?> testClass) {
return replaceCamelCase(super.generateDisplayNameForClass(testClass));
}
@Override
public String generateDisplayNameForNestedClass(Class<?> nestedClass) {
return replaceCamelCase(super.generateDisplayNameForNestedClass(nestedClass));
}
@Override
public String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {
return this.replaceCamelCase(testMethod.getName()) + DisplayNameGenerator.parameterTypesAsString(testMethod);
}
String replaceCamelCase(String camelCase) {
StringBuilder result = new StringBuilder();
result.append(camelCase.charAt(0));
for (int i=1; i<camelCase.length(); i++) {
if (Character.isUpperCase(camelCase.charAt(i))) {
result.append(' ');
result.append(Character.toLowerCase(camelCase.charAt(i)));
} else {
result.append(camelCase.charAt(i));
}
}
return result.toString();
}
}
}
@@ -0,0 +1,20 @@
package com.baeldung.displayname;
import org.junit.jupiter.api.*;
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class ReplaceUnderscoresGeneratorUnitTest {
@Nested
class when_doing_something {
@Test
void then_something_should_happen() {
}
@Test
@DisplayName("@DisplayName takes precedence over generation")
void override_generator() {
}
}
}
@@ -0,0 +1,62 @@
package com.baeldung.extensions.testwatcher;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestWatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestResultLoggerExtension implements TestWatcher, AfterAllCallback {
private static final Logger LOG = LoggerFactory.getLogger(TestResultLoggerExtension.class);
private List<TestResultStatus> testResultsStatus = new ArrayList<>();
private enum TestResultStatus {
SUCCESSFUL, ABORTED, FAILED, DISABLED;
}
@Override
public void testDisabled(ExtensionContext context, Optional<String> reason) {
LOG.info("Test Disabled for test {}: with reason :- {}", context.getDisplayName(), reason.orElse("No reason"));
testResultsStatus.add(TestResultStatus.DISABLED);
}
@Override
public void testSuccessful(ExtensionContext context) {
LOG.info("Test Successful for test {}: ", context.getDisplayName());
testResultsStatus.add(TestResultStatus.SUCCESSFUL);
}
@Override
public void testAborted(ExtensionContext context, Throwable cause) {
LOG.info("Test Aborted for test {}: ", context.getDisplayName());
testResultsStatus.add(TestResultStatus.ABORTED);
}
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
LOG.info("Test Aborted for test {}: ", context.getDisplayName());
testResultsStatus.add(TestResultStatus.FAILED);
}
@Override
public void afterAll(ExtensionContext context) throws Exception {
Map<TestResultStatus, Long> summary = testResultsStatus.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
LOG.info("Test result summary for {} {}", context.getDisplayName(), summary.toString());
}
}
@@ -0,0 +1,36 @@
package com.baeldung.extensions.testwatcher;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.Assert;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(TestResultLoggerExtension.class)
class TestWatcherAPIUnitTest {
@Test
void givenFalseIsTrue_whenTestAbortedThenCaptureResult() {
Assumptions.assumeTrue(false);
}
@Disabled
@Test
void givenTrueIsTrue_whenTestDisabledThenCaptureResult() {
Assert.assertTrue(true);
}
@Test
void givenTrueIsTrue_whenTestAbortedThenCaptureResult() {
Assumptions.assumeTrue(true);
}
@Disabled("This test is disabled")
@Test
void givenFailure_whenTestDisabledWithReason_ThenCaptureResult() {
fail("Not yet implemented");
}
}
@@ -0,0 +1,32 @@
package com.baeldung.failure_vs_error;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author paullatzelsperger
* @since 2019-07-17
*/
class SimpleCalculatorUnitTest {
@Test
void divideNumbers() {
double result = SimpleCalculator.divideNumbers(6, 3);
assertEquals(2, result);
}
@Test
@Disabled("test is expected to fail, disabled so that CI build still goes through")
void divideNumbers_failure() {
double result = SimpleCalculator.divideNumbers(6, 3);
assertEquals(15, result);
}
@Test
@Disabled("test is expected to raise an error, disabled so that CI build still goes through")
void divideNumbers_error() {
SimpleCalculator.divideNumbers(10, 0);
}
}
@@ -0,0 +1,22 @@
package com.baeldung.junit5.testinstance;
import static org.junit.Assert.assertEquals;
import org.junit.jupiter.api.Test;
class AdditionUnitTest {
private int sum = 1;
@Test
void addingTwoToSumReturnsThree() {
sum += 2;
assertEquals(3, sum);
}
@Test
void addingThreeToSumReturnsFour() {
sum += 3;
assertEquals(4, sum);
}
}
@@ -0,0 +1,38 @@
package com.baeldung.junit5.testinstance;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(OrderAnnotation.class)
@TestInstance(Lifecycle.PER_CLASS)
class OrderUnitTest {
private int sum;
@BeforeAll
void init() {
sum = 1;
}
@Test
@Order(1)
void firstTest() {
sum += 2;
assertEquals(3, sum);
}
@Test
@Order(2)
void secondTest() {
sum += 3;
assertEquals(6, sum);
}
}
@@ -0,0 +1,62 @@
package com.baeldung.junit5.testinstance;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class TweetSerializerJUnit4UnitTest {
private static String largeContent;
private static String content;
private static String smallContent;
private static Tweet tweet;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@BeforeClass
public static void setUpFixture() throws IOException {
content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
smallContent = "Lorem ipsum dolor";
largeContent = new String(Files.readAllBytes(Paths.get("src/test/resources/lorem-ipsum.txt")));
tweet = new Tweet();
tweet.setId("AX1346");
}
@Test
public void serializerThrowsExceptionWhenMessageIsTooLarge() throws IOException {
tweet.setContent(largeContent);
expectedException.expect(TweetException.class);
expectedException.expectMessage("Tweet is too large");
new TweetSerializer(tweet).serialize();
}
@Test
public void serializerThrowsExceptionWhenMessageIsTooSmall() throws IOException {
tweet.setContent(smallContent);
expectedException.expect(TweetException.class);
expectedException.expectMessage("Tweet is too small");
new TweetSerializer(tweet).serialize();
}
@Test
public void serializeTweet() throws IOException {
tweet.setContent(content);
byte[] content = new TweetSerializer(tweet).serialize();
assertThat(content, is(notNullValue()));
}
}
@@ -0,0 +1,59 @@
package com.baeldung.junit5.testinstance;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
@TestInstance(Lifecycle.PER_CLASS)
class TweetSerializerUnitTest {
private String largeContent;
private String content;
private String smallContent;
private Tweet tweet;
@BeforeAll
void setUpFixture() throws IOException {
content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
smallContent = "Lorem ipsum dolor";
largeContent = new String(Files.readAllBytes(Paths.get("src/test/resources/lorem-ipsum.txt")));
tweet = new Tweet();
tweet.setId("AX1346");
}
@Test
void serializerThrowsExceptionWhenMessageIsTooLarge() throws IOException {
tweet.setContent(largeContent);
TweetException tweetException = assertThrows(TweetException.class, () -> new TweetSerializer(tweet).serialize());
assertThat(tweetException.getMessage(), is(equalTo("Tweet is too large")));
}
@Test
void serializerThrowsExceptionWhenMessageIsTooSmall() throws IOException {
tweet.setContent(smallContent);
TweetException tweetException = assertThrows(TweetException.class, () -> new TweetSerializer(tweet).serialize());
assertThat(tweetException.getMessage(), is(equalTo("Tweet is too small")));
}
@Test
void serializeTweet() throws IOException {
tweet.setContent(content);
byte[] content = new TweetSerializer(tweet).serialize();
assertThat(content, is(notNullValue()));
}
}
@@ -0,0 +1,4 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.