Skip to content
Open
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
65 changes: 65 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build-and-test:
name: Build, test and report coverage
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up JDK 8
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '8'

- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle', 'gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: ${{ runner.os }}-gradle-

- name: Make Gradle wrapper executable
run: chmod +x ./gradlew

- name: Run tests with coverage
run: ./gradlew clean test jacocoTestReport jacocoTestCoverageVerification --no-daemon --stacktrace

- name: Coverage summary
if: always()
run: |
REPORT=build/reports/jacoco/test/jacocoTestReport.csv
if [ -f "$REPORT" ]; then
awk -F, 'NR>1 { lm += $8; lc += $9 } END {
total = lm + lc;
pct = (total > 0) ? lc * 100 / total : 0;
printf "## JaCoCo coverage\n\n| Metric | Value |\n|---|---|\n| Lines covered | %d / %d |\n| Line coverage | %.2f%% |\n", lc, total, pct
}' "$REPORT" >> "$GITHUB_STEP_SUMMARY"
else
echo "No JaCoCo report found." >> "$GITHUB_STEP_SUMMARY"
fi

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: build/reports/tests/test

- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: jacoco-coverage-report
path: build/reports/jacoco/test
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.idea/
/.idea/
/.gradle/
/build/
47 changes: 46 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ buildscript {
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'jacoco'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

Expand All @@ -25,8 +26,52 @@ repositories {
sourceCompatibility = 1.8
targetCompatibility = 1.8

ext {
junitVersion = '5.2.0'
}

dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("junit:junit")
compile("org.springframework.boot:spring-boot-starter-jdbc")
compile("com.h2database:h2")
runtime("org.springframework.boot:spring-boot-properties-migrator")

testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}

test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
finalizedBy jacocoTestReport
}

jacoco {
toolVersion = "0.8.5"
}

jacocoTestReport {
dependsOn test
reports {
xml.enabled true
html.enabled true
csv.enabled true
}
}

jacocoTestCoverageVerification {
violationRules {
rule {
element = 'BUNDLE'
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.60
}
}
}
}

check.dependsOn jacocoTestCoverageVerification
Empty file modified gradlew
100644 → 100755
Empty file.
28 changes: 28 additions & 0 deletions src/test/java/hello/controller/GreetingControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package hello.controller;

import hello.model.Greeting;
import org.junit.jupiter.api.Test;

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

class GreetingControllerTest {

@Test
void greetingUsesDefaultNameAndIncrementsCounter() {
GreetingController controller = new GreetingController();

Greeting first = controller.greeting("World");
assertEquals(1L, first.getId());
assertEquals("Hello, World!", first.getContent());

Greeting second = controller.greeting("World");
assertEquals(2L, second.getId());
}

@Test
void greetingUsesProvidedName() {
GreetingController controller = new GreetingController();
Greeting greeting = controller.greeting("Matthew");
assertEquals("Hello, Matthew!", greeting.getContent());
}
}
48 changes: 48 additions & 0 deletions src/test/java/hello/controller/HelloControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package hello.controller;

import hello.service.TopicService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

class HelloControllerTest {

private HelloController controller;

@BeforeEach
void setUp() throws Exception {
controller = new HelloController();
Field field = HelloController.class.getDeclaredField("topicService");
field.setAccessible(true);
field.set(controller, new TopicService());
}

@Test
void indexReturnsDateTimeGreeting() {
String result = controller.index();
assertNotNull(result);
assertTrue(result.startsWith("Greetings from Spring Boot!"));
assertTrue(result.contains("Is this a leap year ?"));
}

@Test
void showStringOperationCombinesServiceResults() {
String result = controller.showStringOperation();
assertTrue(result.contains("spring:java:javascript"));
assertTrue(result.contains("java:javascript"));
assertTrue(result.contains("[spring]"));
}

@Test
void showFileOperationReturnsCombinedFileResults() {
String result = controller.showFileOperation();
assertNotNull(result);
assertFalse(result.contains("IO exception"));
assertTrue(result.contains("Find all files in path and sort"));
}
}
69 changes: 69 additions & 0 deletions src/test/java/hello/controller/TopicControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package hello.controller;

import hello.model.Topic;
import hello.service.TopicService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

class TopicControllerTest {

private TopicController controller;

@BeforeEach
void setUp() throws Exception {
controller = new TopicController();
Field field = TopicController.class.getDeclaredField("topicService");
field.setAccessible(true);
field.set(controller, new TopicService());
}

private List<String> ids(List<Topic> topics) {
return topics.stream().map(Topic::getId).collect(Collectors.toList());
}

@Test
void getAllTopicsDelegatesToService() {
assertEquals(Arrays.asList("spring", "java", "javascript"), ids(controller.getAllTopics()));
}

@Test
void getTopicWithIdDelegatesToService() {
assertEquals("Core Java", controller.getTopicWithID("java").getSubjectName());
}

@Test
void addTopicDelegatesToService() {
controller.addTopic(new Topic("go", "Go Lang", "Go Description"));
assertEquals(4, controller.getAllTopics().size());
}

@Test
void updateTopicDelegatesToService() {
controller.updateTopic("java", new Topic("java", "Modern Java", "Updated"));
assertEquals("Modern Java", controller.getTopicWithID("java").getSubjectName());
}

@Test
void deleteTopicDelegatesToService() {
controller.deleteTopic("java");
assertFalse(ids(controller.getAllTopics()).contains("java"));
}

@Test
void filterMinimumLengthForIdDelegatesToService() {
assertEquals(Arrays.asList("javascript"), ids(controller.filterMinimumLengthForId(6)));
}

@Test
void sortTopicsWithIdDelegatesToService() {
assertEquals(Arrays.asList("java", "javascript", "spring"), ids(controller.sortTopicsWithID()));
}
}
33 changes: 33 additions & 0 deletions src/test/java/hello/declaration/TimeClientTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package hello.declaration;

import hello.model.SimpleTimeClient;
import org.junit.jupiter.api.Test;

import java.time.ZoneId;
import java.time.ZonedDateTime;

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

class TimeClientTest {

@Test
void getZoneIdReturnsRequestedZoneWhenValid() {
assertEquals(ZoneId.of("Europe/London"), TimeClient.getZoneId("Europe/London"));
}

@Test
void getZoneIdFallsBackToSystemDefaultWhenInvalid() {
assertEquals(ZoneId.systemDefault(), TimeClient.getZoneId("Not/AZone"));
}

@Test
void getZonedDateTimeUsesLocalDateTimeAndZone() {
SimpleTimeClient client = new SimpleTimeClient();
client.setDateAndTime(2021, 6, 20, 10, 30, 45);

ZonedDateTime zoned = client.getZonedDateTime("America/New_York");

assertEquals(client.getLocalDateTime(), zoned.toLocalDateTime());
assertEquals(ZoneId.of("America/New_York"), zoned.getZone());
}
}
81 changes: 81 additions & 0 deletions src/test/java/hello/model/ModelPojoTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package hello.model;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class ModelPojoTest {

@Test
void topicAllArgsConstructorAndGetters() {
Topic topic = new Topic("java", "Core Java", "Java Description");
assertEquals("java", topic.getId());
assertEquals("Core Java", topic.getSubjectName());
assertEquals("Java Description", topic.getSubjectDescription());
}

@Test
void topicNoArgsConstructorAndSetters() {
Topic topic = new Topic();
topic.setId("go");
topic.setSubjectName("Go Lang");
topic.setSubjectDescription("Go Description");
assertEquals("go", topic.getId());
assertEquals("Go Lang", topic.getSubjectName());
assertEquals("Go Description", topic.getSubjectDescription());
}

@Test
void greetingIsImmutable() {
Greeting greeting = new Greeting(42L, "Hello, World!");
assertEquals(42L, greeting.getId());
assertEquals("Hello, World!", greeting.getContent());
}

@Test
void customerGettersSettersAndToString() {
Customer customer = new Customer(1L, "Josh", "Bloch");
assertEquals(1L, customer.getId());
assertEquals("Josh", customer.getFirstName());
assertEquals("Bloch", customer.getLastName());

customer.setId(2L);
customer.setFirstName("Jeff");
customer.setLastName("Dean");
assertEquals(2L, customer.getId());
assertEquals("Jeff", customer.getFirstName());
assertEquals("Dean", customer.getLastName());

String text = customer.toString();
assertTrue(text.contains("Jeff"));
assertTrue(text.contains("Dean"));
assertTrue(text.contains("id=2"));
}

@Test
void valueGettersSettersAndToString() {
Value value = new Value();
value.setId(7L);
value.setQuote("Stay hungry");
assertEquals(Long.valueOf(7L), value.getId());
assertEquals("Stay hungry", value.getQuote());
assertTrue(value.toString().contains("Stay hungry"));
}

@Test
void quoteGettersSettersAndToString() {
Value value = new Value();
value.setId(1L);
value.setQuote("Work hard");

Quote quote = new Quote();
quote.setType("success");
quote.setValue(value);

assertEquals("success", quote.getType());
assertEquals(value, quote.getValue());
assertTrue(quote.toString().contains("success"));
assertTrue(quote.toString().contains("Work hard"));
}
}
Loading
Loading