Skip to content

Commit

Permalink
Merge pull request #7 from mbland/test-matchers-and-other-tweaks
Browse files Browse the repository at this point in the history
Hoist up Node Gradle plugin, set TestTomcat baseDir, add hasContentType matcher, HTTP status consts
  • Loading branch information
mbland authored Nov 25, 2023
2 parents da33040 + 2719139 commit 5ddd486
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 16 deletions.
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
plugins {
// Apply the foojay-resolver plugin to allow automatic download of JDKs
id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
id("com.github.node-gradle.node") version "7.0.1" apply false
id("com.github.ben-manes.versions") version "0.50.0" apply false
}

Expand Down
2 changes: 1 addition & 1 deletion strcalc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
plugins {
war
jacoco
id("com.github.node-gradle.node") version "7.0.1"
id("com.github.node-gradle.node")
id("com.github.ben-manes.versions")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.mike_bland.training.testing.matchers;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;

import java.net.http.HttpResponse;

// Custom Hamcrest matcher validating the Content-Type header of a HttpResponse.
//
// This could be generalized to check any HTTP header, or collection thereof.
// However, since this is a teaching example, we'll keep it straightforward.
class HasContentType<T> extends TypeSafeMatcher<HttpResponse<T>> {
private final String expected;

// Constructor to register the expected Content-Type value.
HasContentType(String contentType) {
this.expected = contentType;
}

// Helper method to extract the Content-Type value from an HttpResponse.
private String getContentType(HttpResponse<T> resp) {
return resp.headers().firstValue("Content-Type").orElse("");
}

// Performs the actual assertion.
@Override public boolean matchesSafely(HttpResponse<T> resp) {
return getContentType(resp).equals(expected);
}

// Describes the "Expected:" value in assertion failure messages.
@Override public void describeTo(Description description) {
description.appendText(expected);
}

// Describes the actual ("but:") value in assertion failure messages.
@Override public void describeMismatchSafely(
HttpResponse<T> resp, Description description) {
description.appendText(getContentType(resp));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.mike_bland.training.testing.matchers;

import org.hamcrest.Matcher;

import java.net.http.HttpResponse;

// Collection of custom Hamcrest Matcher<T> classes for assertThat() statements.
//
// These tutorials describe how to write Matchers:
//
// - https://hamcrest.org/JavaHamcrest/tutorial
// - https://www.baeldung.com/hamcrest-custom-matchers
//
// Note that these tutorials show the static factory functions defined on the
// same class as the Matcher. However, Hamcrest itself collects these factories
// into its own org.hamcrest.Matchers class for convenience, instead of
// importing one class per Matcher.
public class Matchers {
public static <T> Matcher<HttpResponse<T>> hasContentType(
String contentType) {
return new HasContentType<>(contentType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.mike_bland.training.testing.annotations.MediumTest;
import com.mike_bland.training.testing.utils.PortPicker;
import com.mike_bland.training.testing.utils.TestTomcat;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;

Expand All @@ -20,6 +21,7 @@
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Optional;

import static com.mike_bland.training.testing.matchers.Matchers.hasContentType;
import static com.mike_bland.training.testing.stringcalculator.Servlet.DEFAULT_ROOT;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
Expand Down Expand Up @@ -65,11 +67,8 @@ void servesCorrectLandingPage() throws Exception {

var resp = sendRequest(req);

assertEquals(200, resp.statusCode());
assertEquals(
Optional.of("text/html"),
resp.headers().firstValue("Content-Type")
);
assertEquals(HttpServletResponse.SC_OK, resp.statusCode());
assertThat(resp, hasContentType("text/html"));
assertThat(
resp.body(),
containsString("<title>String Calculator - ")
Expand All @@ -86,11 +85,8 @@ void addEndpointPlaceholder() throws Exception {

var resp = sendRequest(req);

assertEquals(200, resp.statusCode());
assertEquals(
Optional.of("text/plain;charset=UTF-8"),
resp.headers().firstValue("Content-Type")
);
assertEquals(HttpServletResponse.SC_OK, resp.statusCode());
assertThat(resp, hasContentType("text/plain;charset=UTF-8"));
assertEquals("placeholder for /add API endpoint", resp.body());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class TestTomcat {
private final int port;
private final String contextPath;
private final URI uri;
private final File baseDir;
private Tomcat tomcat;
private boolean running;

Expand All @@ -52,12 +53,14 @@ public TestTomcat(int port, String contextPath)
this.uri = URI.create(
String.format("http://localhost:%d%s", port, contextPath)
);
this.baseDir = new File("build/test-tomcat-basedir");
}

public synchronized void start() throws LifecycleException {
if (running) return;
running = true;
tomcat = new Tomcat();
tomcat.setBaseDir(this.baseDir.getAbsolutePath());
tomcat.setPort(port);
tomcat.setSilent(true);

Expand Down Expand Up @@ -127,7 +130,7 @@ public synchronized void stop() throws LifecycleException, IOException {
if (!running) return;
running = false;
tomcat.stop();
deleteBaseDir(port);
deleteBaseDir(this.baseDir);
}

private static String validateContextPath(String contextPath)
Expand All @@ -141,10 +144,7 @@ private static String validateContextPath(String contextPath)
return contextPath;
}

private static void deleteBaseDir(int port) throws IOException {
// The Tomcat.setBaseDir() documentation explains the base dir schema:
// - https://tomcat.apache.org/tomcat-10.1-doc/api/org/apache/catalina/startup/Tomcat.html#setBaseDir(java.lang.String)
final var baseDir = new File("tomcat.%d".formatted(port));
private static void deleteBaseDir(File baseDir) throws IOException {
List<String> failed;

try (var fileStream = Files.walk(baseDir.toPath())) {
Expand Down

0 comments on commit 5ddd486

Please sign in to comment.