├── .github
└── workflows
│ ├── create-diagram.yml
│ └── gradle.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENSE
├── README.md
├── build.gradle
├── diagram.svg
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── mvnw
├── mvnw.cmd
├── pom.xml
├── settings.gradle
└── src
├── main
└── java
│ └── com
│ └── kousenit
│ ├── astro
│ ├── Assignment.java
│ ├── AstroGatewayHttpClient.java
│ ├── AstroGatewayRetrofit.java
│ ├── AstroResponse.java
│ ├── AstroService.java
│ ├── Gateway.java
│ └── astro_data.json
│ ├── hr
│ ├── DefaultTranslationService.java
│ ├── HelloMockito.java
│ ├── InMemoryPersonRepository.java
│ ├── Person.java
│ ├── PersonRepository.java
│ ├── PersonService.java
│ └── TranslationService.java
│ ├── inorder
│ ├── OrderService.java
│ ├── PaymentProcessor.java
│ ├── PaymentService.java
│ └── ShippingService.java
│ ├── pubsub
│ ├── Publisher.java
│ └── Subscriber.java
│ ├── simple
│ ├── AddingMachine.java
│ ├── HelloService.java
│ ├── LoggingDemo.java
│ └── TranslateService.java
│ └── wikipedia
│ ├── BioService.java
│ ├── WikiPage.java
│ ├── WikiQuery.java
│ ├── WikiResponse.java
│ └── WikiUtil.java
└── test
├── java
└── com
│ └── kousenit
│ ├── astro
│ ├── AssignmentTest.java
│ ├── AstroGatewayHttpClientTest.java
│ ├── AstroGatewayRetrofitTest.java
│ ├── AstroServiceTest.java
│ └── FakeGateway.java
│ ├── hr
│ ├── DefaultTranslationServiceTest.java
│ ├── HelloMockitoTest.java
│ ├── InMemoryPersonRepositoryTest.java
│ ├── PersonServiceBDDTest.java
│ ├── PersonServiceTest.java
│ └── PersonTest.java
│ ├── inorder
│ ├── OrderServiceTest.java
│ └── PaymentServiceTest.java
│ ├── pubsub
│ └── PublisherTest.java
│ ├── simple
│ ├── AddingMachineAnnotationTest.java
│ ├── AddingMachineJUnit5Test.java
│ ├── AddingMachineTest.java
│ ├── DocsTest.java
│ ├── HelloServiceTest.java
│ ├── LoggingDemoTests.java
│ ├── LoggingStandardErrorTests.java
│ ├── LoggingWithOutputCaptureTest.java
│ ├── MockFinalTypesTests.java
│ └── MockListOfInteger.java
│ └── wikipedia
│ ├── BioServiceTest.java
│ ├── WikiPageTest.java
│ ├── WikiResponseTest.java
│ └── WikiUtilTest.java
└── resources
├── junit-platform.properties
└── mappings
└── response.json
/.github/workflows/create-diagram.yml:
--------------------------------------------------------------------------------
1 | name: Create diagram
2 | on:
3 | workflow_dispatch: {}
4 | push:
5 | branches:
6 | - main
7 | jobs:
8 | get_data:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout code
12 | uses: actions/checkout@master
13 | - name: Update diagram
14 | uses: githubocto/repo-visualizer@main
15 | with:
16 | excluded_paths: "ignore,.github"
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | name: Java CI
2 | on: [ push ]
3 | jobs:
4 | build:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - uses: actions/checkout@v2
8 | - name: Set up JDK 17
9 | uses: actions/setup-java@v2
10 | with:
11 | distribution: 'temurin'
12 | java-version: 17
13 | - uses: gradle/gradle-build-action@v2.4.2
14 | with:
15 | arguments: build
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | target
3 | bin
4 | classes
5 | .idea
6 | .gradle
7 | .project
8 | .classpath
9 | .settings
10 | out
11 | *.iml
12 | *.ipr
13 | *.iws
14 | .jqwik-database
15 | .DS_Store
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kousen/mockitobook/bb53e9cc29a98b50d355eac8d38620ebcc1ed6fd/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ken Kousen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mockitobook
2 | Code examples for the book _Mockito Made Clear_,
3 | published by Pragmatic Programmers.
4 |
5 | See [the book page](https://pragprog.com/titles/mockito/mockito-made-clear/) for more information.
6 |
7 | 
8 |
9 | You can check out the whole GitHub Action at [diagram.yml](/.github/workflows/diagram.yml). Notice that we're excluding the `ignore` and `.github` folders, using the `excluded_paths` config.
10 |
11 | ## Running the code
12 | To run the code, use the included Gradle wrapper (the `gradlew` scripts for Un*x and Windows) and execute either the `build` or `test` tasks. You can also run individual tests via Gradle, or just load them into your preferred IDE.
13 |
14 | This project uses [Gradle version catalogs](https://docs.gradle.org/current/userguide/platforms.html#sub:central-declaration-of-dependencies), which require Gradle 7.4 or higher. The included wrapper is higher than that. The dependency versions are inside the `libs.versions.toml` file in the `gradle` directory, which are used inside `build.gradle`.
15 |
16 | See also the Mockito play list at my [YouTube channel](https://www.youtube.com/@talesfromthejarside?sub_confirmation=1).
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Using Gradle version catalogs -- see gradle/libs.versions.toml
2 | plugins {
3 | id 'java'
4 | id 'jacoco'
5 | alias(libs.plugins.versions)
6 | alias(libs.plugins.version.catalog.update)
7 | }
8 |
9 | group 'com.kousenit'
10 | version '1.0'
11 |
12 | // Java 11+ needed for HttpClient
13 | java {
14 | toolchain {
15 | languageVersion.set(JavaLanguageVersion.of(17))
16 | }
17 | }
18 |
19 | repositories {
20 | mavenCentral()
21 | }
22 |
23 | dependencies {
24 | // JUnit bundle (includes vintage engine)
25 | testImplementation libs.bundles.junit
26 |
27 | // Mockito bundle (inline and JUnit Jupiter engine)
28 | testImplementation libs.bundles.mockito
29 |
30 | // AssertJ
31 | testImplementation libs.assertj
32 |
33 | // Spring test library (don't move to 3.* unless Java 17+)
34 | testImplementation 'org.springframework.boot:spring-boot-test:3.2.5'
35 |
36 | // Retrofit
37 | implementation libs.retrofit.core
38 | implementation libs.retrofit.gson
39 |
40 | // Make security warning go away for retrofit transitive dep
41 | implementation 'com.squareup.okhttp3:okhttp:4.12.0'
42 |
43 | // Jackson JSON library
44 | implementation libs.jackson
45 |
46 | // Gson
47 | implementation libs.gson
48 | }
49 |
50 | tasks.named('test',Test) {
51 | useJUnitPlatform()
52 | maxParallelForks = (int) (Runtime.runtime.availableProcessors() / 2 + 1)
53 | }
54 |
55 | jacocoTestReport.dependsOn(test)
--------------------------------------------------------------------------------
/diagram.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.caching=true
2 | org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | assertj = "3.25.3"
3 | gson = "2.10.1"
4 | jackson = "2.17.0"
5 | junit = "5.11.0-M1"
6 | junit-platform = "1.11.0-M1"
7 | mockito = "5.11.0"
8 | retrofit = "2.11.0"
9 |
10 | [libraries]
11 | assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" }
12 | gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
13 | jackson = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
14 | junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
15 | junit-platform = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit-platform" }
16 | junit-vintage = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit" }
17 | mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" }
18 | mockito-junit = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" }
19 | retrofit-core = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
20 | retrofit-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
21 |
22 | [bundles]
23 | junit = [
24 | "junit-jupiter",
25 | "junit-platform",
26 | "junit-vintage",
27 | ]
28 | mockito = [
29 | "mockito-core",
30 | "mockito-junit",
31 | ]
32 |
33 | [plugins]
34 | version-catalog-update = "nl.littlerobots.version-catalog-update:0.8.4"
35 | versions = "com.github.ben-manes.versions:0.51.0"
36 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kousen/mockitobook/bb53e9cc29a98b50d355eac8d38620ebcc1ed6fd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MSYS* | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Apache Maven Wrapper startup batch script, version 3.1.1
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | # e.g. to debug Maven itself, use
32 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | # ----------------------------------------------------------------------------
35 |
36 | if [ -z "$MAVEN_SKIP_RC" ] ; then
37 |
38 | if [ -f /usr/local/etc/mavenrc ] ; then
39 | . /usr/local/etc/mavenrc
40 | fi
41 |
42 | if [ -f /etc/mavenrc ] ; then
43 | . /etc/mavenrc
44 | fi
45 |
46 | if [ -f "$HOME/.mavenrc" ] ; then
47 | . "$HOME/.mavenrc"
48 | fi
49 |
50 | fi
51 |
52 | # OS specific support. $var _must_ be set to either true or false.
53 | cygwin=false;
54 | darwin=false;
55 | mingw=false
56 | case "`uname`" in
57 | CYGWIN*) cygwin=true ;;
58 | MINGW*) mingw=true;;
59 | Darwin*) darwin=true
60 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
61 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
62 | if [ -z "$JAVA_HOME" ]; then
63 | if [ -x "/usr/libexec/java_home" ]; then
64 | JAVA_HOME="`/usr/libexec/java_home`"; export JAVA_HOME
65 | else
66 | JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
67 | fi
68 | fi
69 | ;;
70 | esac
71 |
72 | if [ -z "$JAVA_HOME" ] ; then
73 | if [ -r /etc/gentoo-release ] ; then
74 | JAVA_HOME=`java-config --jre-home`
75 | fi
76 | fi
77 |
78 | # For Cygwin, ensure paths are in UNIX format before anything is touched
79 | if $cygwin ; then
80 | [ -n "$JAVA_HOME" ] &&
81 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
82 | [ -n "$CLASSPATH" ] &&
83 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
84 | fi
85 |
86 | # For Mingw, ensure paths are in UNIX format before anything is touched
87 | if $mingw ; then
88 | [ -n "$JAVA_HOME" ] &&
89 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
90 | fi
91 |
92 | if [ -z "$JAVA_HOME" ]; then
93 | javaExecutable="`which javac`"
94 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
95 | # readlink(1) is not available as standard on Solaris 10.
96 | readLink=`which readlink`
97 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
98 | if $darwin ; then
99 | javaHome="`dirname \"$javaExecutable\"`"
100 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
101 | else
102 | javaExecutable="`readlink -f \"$javaExecutable\"`"
103 | fi
104 | javaHome="`dirname \"$javaExecutable\"`"
105 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
106 | JAVA_HOME="$javaHome"
107 | export JAVA_HOME
108 | fi
109 | fi
110 | fi
111 |
112 | if [ -z "$JAVACMD" ] ; then
113 | if [ -n "$JAVA_HOME" ] ; then
114 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
115 | # IBM's JDK on AIX uses strange locations for the executables
116 | JAVACMD="$JAVA_HOME/jre/sh/java"
117 | else
118 | JAVACMD="$JAVA_HOME/bin/java"
119 | fi
120 | else
121 | JAVACMD="`\\unset -f command; \\command -v java`"
122 | fi
123 | fi
124 |
125 | if [ ! -x "$JAVACMD" ] ; then
126 | echo "Error: JAVA_HOME is not defined correctly." >&2
127 | echo " We cannot execute $JAVACMD" >&2
128 | exit 1
129 | fi
130 |
131 | if [ -z "$JAVA_HOME" ] ; then
132 | echo "Warning: JAVA_HOME environment variable is not set."
133 | fi
134 |
135 | # traverses directory structure from process work directory to filesystem root
136 | # first directory with .mvn subdirectory is considered project base directory
137 | find_maven_basedir() {
138 | if [ -z "$1" ]
139 | then
140 | echo "Path not specified to find_maven_basedir"
141 | return 1
142 | fi
143 |
144 | basedir="$1"
145 | wdir="$1"
146 | while [ "$wdir" != '/' ] ; do
147 | if [ -d "$wdir"/.mvn ] ; then
148 | basedir=$wdir
149 | break
150 | fi
151 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
152 | if [ -d "${wdir}" ]; then
153 | wdir=`cd "$wdir/.."; pwd`
154 | fi
155 | # end of workaround
156 | done
157 | printf '%s' "$(cd "$basedir"; pwd)"
158 | }
159 |
160 | # concatenates all lines of a file
161 | concat_lines() {
162 | if [ -f "$1" ]; then
163 | echo "$(tr -s '\n' ' ' < "$1")"
164 | fi
165 | }
166 |
167 | BASE_DIR=$(find_maven_basedir "$(dirname $0)")
168 | if [ -z "$BASE_DIR" ]; then
169 | exit 1;
170 | fi
171 |
172 | MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
173 | if [ "$MVNW_VERBOSE" = true ]; then
174 | echo $MAVEN_PROJECTBASEDIR
175 | fi
176 |
177 | ##########################################################################################
178 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
179 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
180 | ##########################################################################################
181 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
182 | if [ "$MVNW_VERBOSE" = true ]; then
183 | echo "Found .mvn/wrapper/maven-wrapper.jar"
184 | fi
185 | else
186 | if [ "$MVNW_VERBOSE" = true ]; then
187 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
188 | fi
189 | if [ -n "$MVNW_REPOURL" ]; then
190 | wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
191 | else
192 | wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
193 | fi
194 | while IFS="=" read key value; do
195 | case "$key" in (wrapperUrl) wrapperUrl="$value"; break ;;
196 | esac
197 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
198 | if [ "$MVNW_VERBOSE" = true ]; then
199 | echo "Downloading from: $wrapperUrl"
200 | fi
201 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
202 | if $cygwin; then
203 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
204 | fi
205 |
206 | if command -v wget > /dev/null; then
207 | QUIET="--quiet"
208 | if [ "$MVNW_VERBOSE" = true ]; then
209 | echo "Found wget ... using wget"
210 | QUIET=""
211 | fi
212 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
213 | wget $QUIET "$wrapperUrl" -O "$wrapperJarPath"
214 | else
215 | wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath"
216 | fi
217 | [ $? -eq 0 ] || rm -f "$wrapperJarPath"
218 | elif command -v curl > /dev/null; then
219 | QUIET="--silent"
220 | if [ "$MVNW_VERBOSE" = true ]; then
221 | echo "Found curl ... using curl"
222 | QUIET=""
223 | fi
224 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
225 | curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L
226 | else
227 | curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L
228 | fi
229 | [ $? -eq 0 ] || rm -f "$wrapperJarPath"
230 | else
231 | if [ "$MVNW_VERBOSE" = true ]; then
232 | echo "Falling back to using Java to download"
233 | fi
234 | javaSource="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
235 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class"
236 | # For Cygwin, switch paths to Windows format before running javac
237 | if $cygwin; then
238 | javaSource=`cygpath --path --windows "$javaSource"`
239 | javaClass=`cygpath --path --windows "$javaClass"`
240 | fi
241 | if [ -e "$javaSource" ]; then
242 | if [ ! -e "$javaClass" ]; then
243 | if [ "$MVNW_VERBOSE" = true ]; then
244 | echo " - Compiling MavenWrapperDownloader.java ..."
245 | fi
246 | # Compiling the Java class
247 | ("$JAVA_HOME/bin/javac" "$javaSource")
248 | fi
249 | if [ -e "$javaClass" ]; then
250 | # Running the downloader
251 | if [ "$MVNW_VERBOSE" = true ]; then
252 | echo " - Running MavenWrapperDownloader.java ..."
253 | fi
254 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
255 | fi
256 | fi
257 | fi
258 | fi
259 | ##########################################################################################
260 | # End of extension
261 | ##########################################################################################
262 |
263 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
264 |
265 | # For Cygwin, switch paths to Windows format before running java
266 | if $cygwin; then
267 | [ -n "$JAVA_HOME" ] &&
268 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
269 | [ -n "$CLASSPATH" ] &&
270 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
271 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
272 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
273 | fi
274 |
275 | # Provide a "standardized" way to retrieve the CLI args that will
276 | # work with both Windows and non-Windows executions.
277 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
278 | export MAVEN_CMD_LINE_ARGS
279 |
280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
281 |
282 | exec "$JAVACMD" \
283 | $MAVEN_OPTS \
284 | $MAVEN_DEBUG_OPTS \
285 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
286 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
287 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
288 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Apache Maven Wrapper startup batch script, version 3.1.1
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
28 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
29 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
30 | @REM e.g. to debug Maven itself, use
31 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
32 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
33 | @REM ----------------------------------------------------------------------------
34 |
35 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
36 | @echo off
37 | @REM set title of command window
38 | title %0
39 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
40 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
41 |
42 | @REM set %HOME% to equivalent of $HOME
43 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
44 |
45 | @REM Execute a user defined script before this one
46 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
47 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
48 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
49 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
50 | :skipRcPre
51 |
52 | @setlocal
53 |
54 | set ERROR_CODE=0
55 |
56 | @REM To isolate internal variables from possible post scripts, we use another setlocal
57 | @setlocal
58 |
59 | @REM ==== START VALIDATION ====
60 | if not "%JAVA_HOME%" == "" goto OkJHome
61 |
62 | echo.
63 | echo Error: JAVA_HOME not found in your environment. >&2
64 | echo Please set the JAVA_HOME variable in your environment to match the >&2
65 | echo location of your Java installation. >&2
66 | echo.
67 | goto error
68 |
69 | :OkJHome
70 | if exist "%JAVA_HOME%\bin\java.exe" goto init
71 |
72 | echo.
73 | echo Error: JAVA_HOME is set to an invalid directory. >&2
74 | echo JAVA_HOME = "%JAVA_HOME%" >&2
75 | echo Please set the JAVA_HOME variable in your environment to match the >&2
76 | echo location of your Java installation. >&2
77 | echo.
78 | goto error
79 |
80 | @REM ==== END VALIDATION ====
81 |
82 | :init
83 |
84 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
85 | @REM Fallback to current working directory if not found.
86 |
87 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
88 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
89 |
90 | set EXEC_DIR=%CD%
91 | set WDIR=%EXEC_DIR%
92 | :findBaseDir
93 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
94 | cd ..
95 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
96 | set WDIR=%CD%
97 | goto findBaseDir
98 |
99 | :baseDirFound
100 | set MAVEN_PROJECTBASEDIR=%WDIR%
101 | cd "%EXEC_DIR%"
102 | goto endDetectBaseDir
103 |
104 | :baseDirNotFound
105 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
106 | cd "%EXEC_DIR%"
107 |
108 | :endDetectBaseDir
109 |
110 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
111 |
112 | @setlocal EnableExtensions EnableDelayedExpansion
113 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
114 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
115 |
116 | :endReadAdditionalConfig
117 |
118 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
123 |
124 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
125 | IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
126 | )
127 |
128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
130 | if exist %WRAPPER_JAR% (
131 | if "%MVNW_VERBOSE%" == "true" (
132 | echo Found %WRAPPER_JAR%
133 | )
134 | ) else (
135 | if not "%MVNW_REPOURL%" == "" (
136 | SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
137 | )
138 | if "%MVNW_VERBOSE%" == "true" (
139 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
140 | echo Downloading from: %WRAPPER_URL%
141 | )
142 |
143 | powershell -Command "&{"^
144 | "$webclient = new-object System.Net.WebClient;"^
145 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
146 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
147 | "}"^
148 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
149 | "}"
150 | if "%MVNW_VERBOSE%" == "true" (
151 | echo Finished downloading %WRAPPER_JAR%
152 | )
153 | )
154 | @REM End of extension
155 |
156 | @REM Provide a "standardized" way to retrieve the CLI args that will
157 | @REM work with both Windows and non-Windows executions.
158 | set MAVEN_CMD_LINE_ARGS=%*
159 |
160 | %MAVEN_JAVA_EXE% ^
161 | %JVM_CONFIG_MAVEN_PROPS% ^
162 | %MAVEN_OPTS% ^
163 | %MAVEN_DEBUG_OPTS% ^
164 | -classpath %WRAPPER_JAR% ^
165 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
166 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
167 | if ERRORLEVEL 1 goto error
168 | goto end
169 |
170 | :error
171 | set ERROR_CODE=1
172 |
173 | :end
174 | @endlocal & set ERROR_CODE=%ERROR_CODE%
175 |
176 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
177 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
178 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
179 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
180 | :skipRcPost
181 |
182 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
183 | if "%MAVEN_BATCH_PAUSE%"=="on" pause
184 |
185 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
186 |
187 | cmd /C exit /B %ERROR_CODE%
188 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.kousenit
8 | mockitobook
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 11
13 | 11
14 | UTF-8
15 |
16 |
17 |
18 | org.mockito
19 | mockito-core
20 | 5.4.0
21 |
22 |
23 | org.mockito
24 | mockito-junit-jupiter
25 | 5.4.0
26 |
27 |
28 | org.junit.jupiter
29 | junit-jupiter
30 | 5.9.2
31 | test
32 |
33 |
34 | org.junit.vintage
35 | junit-vintage-engine
36 | 5.9.2
37 | test
38 |
39 |
40 | org.assertj
41 | assertj-core
42 | 3.24.2
43 | test
44 |
45 |
46 | com.google.code.gson
47 | gson
48 | 2.10.1
49 |
50 |
51 | com.fasterxml.jackson.core
52 | jackson-databind
53 | 2.14.2
54 |
55 |
56 | com.squareup.retrofit2
57 | retrofit
58 | 2.9.0
59 |
60 |
61 | com.squareup.retrofit2
62 | converter-gson
63 | 2.9.0
64 |
65 |
66 |
67 |
68 |
69 | org.apache.maven.plugins
70 | maven-surefire-plugin
71 | 3.0.0-M8
72 |
73 |
74 | org.apache.maven.plugins
75 | maven-compiler-plugin
76 | 3.10.1
77 |
78 | 11
79 | 11
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.gradle.enterprise' version '3.8.1'
3 | }
4 |
5 | gradleEnterprise {
6 | buildScan {
7 | termsOfServiceUrl = "https://gradle.com/terms-of-service"
8 | termsOfServiceAgree = "yes"
9 | }
10 | }
11 |
12 | rootProject.name = 'mockitobook'
13 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/astro/Assignment.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | public class Assignment {
4 | private final String name;
5 | private final String craft;
6 |
7 | public Assignment(String name, String craft) {
8 | this.name = name;
9 | this.craft = craft;
10 | }
11 |
12 | public String getCraft() {
13 | return craft;
14 | }
15 |
16 | public String getName() {
17 | return name;
18 | }
19 |
20 | @Override
21 | public String toString() {
22 | return "Assignment{" +
23 | "name='" + name + '\'' +
24 | ", craft='" + craft + '\'' +
25 | '}';
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/astro/AstroGatewayHttpClient.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import com.google.gson.Gson;
4 |
5 | import java.io.IOException;
6 | import java.net.URI;
7 | import java.net.http.HttpClient;
8 | import java.net.http.HttpRequest;
9 | import java.net.http.HttpResponse;
10 | import java.time.Duration;
11 |
12 | @SuppressWarnings("HttpUrlsUsage")
13 | public class AstroGatewayHttpClient implements Gateway {
14 | private static final String DEFAULT_URL = "http://api.open-notify.org/";
15 | private final String url;
16 |
17 | public AstroGatewayHttpClient() {
18 | this(DEFAULT_URL);
19 | }
20 |
21 | public AstroGatewayHttpClient(String url) {
22 | this.url = url;
23 | }
24 |
25 | @Override
26 | public AstroResponse getResponse() {
27 | HttpClient client = HttpClient.newHttpClient();
28 | HttpRequest request = HttpRequest.newBuilder()
29 | .uri(URI.create(url + "astros.json"))
30 | .timeout(Duration.ofSeconds(2))
31 | .build();
32 | try {
33 | HttpResponse response =
34 | client.send(request, HttpResponse.BodyHandlers.ofString());
35 | return new Gson().fromJson(response.body(), AstroResponse.class);
36 | } catch (IOException | InterruptedException e) {
37 | throw new RuntimeException(e);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/astro/AstroGatewayRetrofit.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import retrofit2.Call;
4 | import retrofit2.Retrofit;
5 | import retrofit2.converter.gson.GsonConverterFactory;
6 | import retrofit2.http.GET;
7 |
8 | import java.io.IOException;
9 |
10 | @SuppressWarnings("HttpUrlsUsage")
11 | public class AstroGatewayRetrofit implements Gateway {
12 | private static final String DEFAULT_URL = "http://api.open-notify.org/";
13 | private final String url;
14 |
15 | public AstroGatewayRetrofit() {
16 | this(DEFAULT_URL);
17 | }
18 |
19 | public AstroGatewayRetrofit(String url) {
20 | this.url = url;
21 | }
22 |
23 | @Override
24 | public AstroResponse getResponse() {
25 | Retrofit retrofit = new Retrofit.Builder()
26 | .baseUrl(url)
27 | .addConverterFactory(GsonConverterFactory.create())
28 | .build();
29 |
30 | OpenNotify openNotify = retrofit.create(OpenNotify.class);
31 | try {
32 | return openNotify.getAstronautsInSpace().execute().body();
33 | } catch (IOException e) {
34 | throw new RuntimeException(e);
35 | }
36 | }
37 |
38 | interface OpenNotify {
39 | @GET("astros.json")
40 | Call getAstronautsInSpace();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/astro/AstroResponse.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import java.util.List;
4 |
5 | public class AstroResponse {
6 |
7 | private final int number;
8 | private final String message;
9 | private final List people;
10 |
11 | public AstroResponse(int number,
12 | String message,
13 | List people) {
14 | this.number = number;
15 | this.message = message;
16 | this.people = people;
17 | }
18 |
19 | public int getNumber() {
20 | return number;
21 | }
22 |
23 | public String getMessage() {
24 | return message;
25 | }
26 |
27 | public List getPeople() {
28 | return people;
29 | }
30 |
31 | @Override
32 | public String toString() {
33 | return "AstroResponse{" +
34 | "number=" + number +
35 | ", message='" + message + '\'' +
36 | ", people=" + people +
37 | '}';
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/astro/AstroService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import java.util.Map;
4 | import java.util.stream.Collectors;
5 |
6 | public class AstroService {
7 | private final Gateway gateway;
8 |
9 | public AstroService(Gateway gateway) {
10 | this.gateway = gateway;
11 | }
12 |
13 | public Map getAstroData() {
14 | AstroResponse response = gateway.getResponse();
15 | return groupByCraft(response);
16 | }
17 |
18 | private Map groupByCraft(AstroResponse data) {
19 | return data.getPeople().stream()
20 | .collect(Collectors.groupingBy(
21 | Assignment::getCraft, Collectors.counting()));
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/astro/Gateway.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | public interface Gateway {
4 | T getResponse();
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/astro/astro_data.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "success",
3 | "people": [
4 | {
5 | "name": "Mark Vande Hei",
6 | "craft": "ISS"
7 | },
8 | {
9 | "name": "Pyotr Dubrov",
10 | "craft": "ISS"
11 | },
12 | {
13 | "name": "Anton Shkaplerov",
14 | "craft": "ISS"
15 | },
16 | {
17 | "name": "Zhai Zhigang",
18 | "craft": "Shenzhou 13"
19 | },
20 | {
21 | "name": "Wang Yaping",
22 | "craft": "Shenzhou 13"
23 | },
24 | {
25 | "name": "Ye Guangfu",
26 | "craft": "Shenzhou 13"
27 | },
28 | {
29 | "name": "Raja Chari",
30 | "craft": "ISS"
31 | },
32 | {
33 | "name": "Tom Marshburn",
34 | "craft": "ISS"
35 | },
36 | {
37 | "name": "Kayla Barron",
38 | "craft": "ISS"
39 | },
40 | {
41 | "name": "Matthias Maurer",
42 | "craft": "ISS"
43 | }
44 | ],
45 | "number": 10
46 | }
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/hr/DefaultTranslationService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | public class DefaultTranslationService implements TranslationService {
4 | public String translate(String text, String sourceLanguage, String targetLanguage) {
5 | return TranslationService.super.translate(text, "en", "en");
6 | }
7 |
8 | public String translate(String text) {
9 | return text;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/hr/HelloMockito.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import java.util.Optional;
4 |
5 | public class HelloMockito {
6 | private String greeting = "Hello, %s, from Mockito!";
7 | private final PersonRepository personRepository;
8 | private final TranslationService translationService;
9 |
10 | public HelloMockito(PersonRepository personRepository, TranslationService translationService) {
11 | this.personRepository = personRepository;
12 | this.translationService = translationService;
13 | }
14 |
15 | public String greet(int id, String sourceLanguage, String targetLanguage) {
16 | Optional person = personRepository.findById(id);
17 | String name = person.map(Person::getFirst).orElse("World");
18 | return translationService.translate(
19 | String.format(greeting, name), sourceLanguage, targetLanguage);
20 | }
21 |
22 |
23 | public HelloMockito(PersonRepository personRepository) {
24 | this(personRepository, new DefaultTranslationService());
25 | }
26 |
27 | public HelloMockito(TranslationService service) {
28 | this(new InMemoryPersonRepository(), service);
29 | }
30 |
31 | @SuppressWarnings("unused")
32 | public String greet(int id) {
33 | Optional person = personRepository.findById(id);
34 | String name = person.map(Person::getFirst).orElse("World");
35 | return translationService.translate(String.format(greeting, name));
36 | }
37 |
38 | public String greet(Person person, String sourceLanguage, String targetLanguage) {
39 | return translationService.translate(
40 | String.format(greeting, person.getFirst()), sourceLanguage, targetLanguage);
41 | }
42 |
43 | public void setGreeting(String greeting) {
44 | this.greeting = greeting;
45 | }
46 |
47 | public String getGreeting() {
48 | return greeting;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/hr/InMemoryPersonRepository.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import java.util.*;
4 | import java.util.stream.Collectors;
5 |
6 | public class InMemoryPersonRepository implements PersonRepository {
7 | private final List people = new ArrayList<>();
8 |
9 | @Override
10 | public final Person save(Person person) {
11 | synchronized (people) {
12 | people.add(person);
13 | }
14 | return person;
15 | }
16 |
17 | @Override
18 | public Optional findById(int id) {
19 | Map peopleMap =
20 | people.stream().collect(Collectors.toMap(Person::getId, p -> p));
21 | return Optional.ofNullable(peopleMap.get(id));
22 | }
23 |
24 | @Override
25 | public List findAll() {
26 | return people;
27 | }
28 |
29 | @Override
30 | public long count() {
31 | return people.size();
32 | }
33 |
34 | @Override
35 | public final void delete(Person person) {
36 | synchronized (people) {
37 | people.remove(person);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/hr/Person.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import java.time.LocalDate;
4 | import java.util.Objects;
5 |
6 | public class Person {
7 | private final Integer id;
8 | private final String first;
9 | private final String last;
10 | private final LocalDate dob;
11 |
12 | Person(Integer id, String first, String last, LocalDate dob) {
13 | this.id = id;
14 | this.first = first;
15 | this.last = last;
16 | this.dob = dob;
17 | }
18 |
19 | public Integer getId() {
20 | return id;
21 | }
22 |
23 | public String getFirst() {
24 | return first;
25 | }
26 |
27 | public String getLast() {
28 | return last;
29 | }
30 |
31 | public LocalDate getDob() {
32 | return dob;
33 | }
34 |
35 | @Override
36 | public boolean equals(Object obj) {
37 | if (obj == this) return true;
38 | if (obj == null || obj.getClass() != this.getClass()) return false;
39 | Person that = (Person) obj;
40 | return Objects.equals(this.id, that.id) &&
41 | Objects.equals(this.first, that.first) &&
42 | Objects.equals(this.last, that.last) &&
43 | Objects.equals(this.dob, that.dob);
44 | }
45 |
46 | @Override
47 | public int hashCode() {
48 | return Objects.hash(id, first, last, dob);
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return "Person[" +
54 | "id=" + id + ", " +
55 | "first=" + first + ", " +
56 | "last=" + last + ", " +
57 | "dob=" + dob + ']';
58 | }
59 | }
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/hr/PersonRepository.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import java.util.List;
4 | import java.util.Optional;
5 |
6 | public interface PersonRepository {
7 | Person save(Person person);
8 | Optional findById(int id);
9 | List findAll();
10 | long count();
11 | void delete(Person person);
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/hr/PersonService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import java.time.LocalDate;
4 | import java.util.Arrays;
5 | import java.util.List;
6 | import java.util.Optional;
7 | import java.util.concurrent.CompletableFuture;
8 | import java.util.stream.Collectors;
9 |
10 | public class PersonService {
11 | private final PersonRepository repository;
12 |
13 | public PersonService(PersonRepository repository) {
14 | this.repository = repository;
15 | }
16 |
17 | public List savePeople(Person... person) {
18 | return Arrays.stream(person)
19 | .map(repository::save)
20 | .map(Person::getId)
21 | .collect(Collectors.toList());
22 | }
23 |
24 | public void asyncSavePerson(Person person, long delay) {
25 | CompletableFuture.runAsync(() -> {
26 | System.out.println("Running on thread " + Thread.currentThread().getName());
27 | try {
28 | Thread.sleep(delay);
29 | } catch (InterruptedException ignored) {
30 | }
31 | repository.save(person);
32 | });
33 | }
34 |
35 | public List getLastNames() {
36 | return repository.findAll().stream()
37 | .map(Person::getLast)
38 | .collect(Collectors.toList());
39 | }
40 |
41 | public List findByIds(int... ids) {
42 | return Arrays.stream(ids)
43 | .mapToObj(repository::findById)
44 | .filter(Optional::isPresent)
45 | .map(Optional::get)
46 | .collect(Collectors.toList());
47 | }
48 |
49 | public Integer getHighestId() {
50 | return repository.findAll().stream()
51 | .map(Person::getId)
52 | .max(Integer::compareTo).orElse(0);
53 | }
54 |
55 | public Person createPerson(int id, String first, String last, LocalDate dob) {
56 | Person person = new Person(id, first, last, dob);
57 | return repository.save(person);
58 | }
59 |
60 | public Person createPerson(int id, String first, String last, String dobString) {
61 | Person person = new Person(id, first, last, LocalDate.parse(dobString));
62 | return repository.save(person);
63 | }
64 |
65 | public long getTotalPeople() {
66 | return repository.count();
67 | }
68 |
69 | public void deleteAll() {
70 | repository.findAll()
71 | .forEach(repository::delete);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/hr/TranslationService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | public interface TranslationService {
4 |
5 | default String translate(String text, String sourceLanguage, String targetLanguage) {
6 | return text;
7 | }
8 |
9 | String translate(String text);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/inorder/OrderService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.inorder;
2 |
3 | public class OrderService {
4 | // Dependencies of the class under test
5 | private final PaymentService paymentService;
6 | private final ShippingService shippingService;
7 |
8 | // Constructor to make it easy to inject the dependencies
9 | public OrderService(PaymentService paymentService, ShippingService shippingService) {
10 | this.paymentService = paymentService;
11 | this.shippingService = shippingService;
12 | }
13 |
14 | // Need to test this method
15 | public boolean processOrder(double amount, String address) {
16 | if (paymentService.processPayment(amount)) {
17 | return shippingService.shipProduct(address);
18 | } else {
19 | return false;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/inorder/PaymentProcessor.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.inorder;
2 |
3 | public interface PaymentProcessor {
4 | boolean authorizePayment(double amount);
5 | boolean capturePayment(); // request the authorized funds
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/inorder/PaymentService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.inorder;
2 |
3 | public class PaymentService {
4 | // Dependency of the class under test
5 | private final PaymentProcessor processor;
6 |
7 | // Constructor to make it easy to inject the dependency
8 | public PaymentService(PaymentProcessor processor) {
9 | this.processor = processor;
10 | }
11 |
12 | // Need to test this method
13 | public boolean processPayment(double amount) {
14 | // Payment must be authorized before collecting the money
15 | if (processor.authorizePayment(amount)) {
16 | return processor.capturePayment();
17 | }
18 | return false;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/inorder/ShippingService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.inorder;
2 |
3 | public interface ShippingService {
4 | boolean shipProduct(String address);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/pubsub/Publisher.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.pubsub;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | // Adapted from a similar example in the Spock framework
7 | public class Publisher {
8 | private final List subscribers = new ArrayList<>();
9 |
10 | public void subscribe(Subscriber sub) {
11 | subscribers.add(sub);
12 | }
13 |
14 | // Want to test this method
15 | public void send(String message) {
16 | for (Subscriber sub : subscribers) {
17 | try {
18 | sub.onNext(message);
19 | } catch (Exception ignored) {
20 | // evil, but what can you do?
21 | }
22 | }
23 | }
24 |
25 | public void sendParallel(String message) {
26 | subscribers.parallelStream().forEach(sub -> {
27 | try {
28 | sub.onNext(message);
29 | } catch (Exception ignored) {
30 | }
31 | });
32 | }
33 |
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/pubsub/Subscriber.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.pubsub;
2 |
3 | public interface Subscriber {
4 | void onNext(String message);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/simple/AddingMachine.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import java.util.List;
4 |
5 | public class AddingMachine {
6 | private final List numbers;
7 |
8 | public AddingMachine(List numbers) {
9 | this.numbers = numbers;
10 | }
11 |
12 | @SuppressWarnings("ForLoopReplaceableByForEach")
13 | public int getTotalUsingLoop() {
14 | int total = 0;
15 | int count = numbers.size();
16 | for (int i = 0; i < count; i++) {
17 | total += numbers.get(i);
18 | }
19 | return total;
20 | }
21 |
22 | public int getTotalUsingIterable() {
23 | int total = 0;
24 | for (int n : numbers) {
25 | total += n;
26 | }
27 | return total;
28 | }
29 |
30 | public int getTotalUsingStream() {
31 | return numbers.stream()
32 | .mapToInt(Integer::valueOf)
33 | .sum();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/simple/HelloService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | public class HelloService {
4 |
5 | private final TranslateService translateService;
6 |
7 | public HelloService(TranslateService translateService) {
8 | this.translateService = translateService;
9 | }
10 |
11 | public String greet(String name, String language) {
12 | String greeting = "Hello, " + name + "!";
13 | return translateService.translate(greeting, language);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/simple/LoggingDemo.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import java.util.logging.Logger;
4 |
5 | public class LoggingDemo {
6 | private final Logger logger;
7 |
8 | public LoggingDemo(Logger logger) {
9 | this.logger = logger;
10 | }
11 |
12 | public void doStuff(String message) {
13 | System.out.printf("Doing useful stuff: %s%n", message);
14 | logger.info(message);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/simple/TranslateService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | public class TranslateService {
4 |
5 | // Translate from English to whatever locale is specified
6 | public String translate(String text, String language) {
7 | return language + " translation: " + text;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/wikipedia/BioService.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 | import java.util.stream.Collectors;
6 |
7 | public class BioService {
8 | private final List pageNames;
9 |
10 | public BioService(String... pageNames) {
11 | this.pageNames = Arrays.stream(pageNames)
12 | .collect(Collectors.toList());
13 | }
14 |
15 | public List getBios() {
16 | return pageNames.stream()
17 | .map(WikiUtil::getWikipediaExtract)
18 | .collect(Collectors.toList());
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/wikipedia/WikiPage.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 |
5 | @SuppressWarnings("unused")
6 | public class WikiPage {
7 | @JsonIgnore
8 | private int pageid;
9 | @JsonIgnore
10 | private int ns;
11 | private String title;
12 | private String extract;
13 | @JsonIgnore
14 | private boolean missing;
15 |
16 | public int getPageid() {
17 | return pageid;
18 | }
19 |
20 | public void setPageid(int pageid) {
21 | this.pageid = pageid;
22 | }
23 |
24 | public int getNs() {
25 | return ns;
26 | }
27 |
28 | public void setNs(int ns) {
29 | this.ns = ns;
30 | }
31 |
32 | public String getTitle() {
33 | return title;
34 | }
35 |
36 | public void setTitle(String title) {
37 | this.title = title;
38 | }
39 |
40 | public String getExtract() {
41 | return extract;
42 | }
43 |
44 | public void setExtract(String extract) {
45 | this.extract = extract;
46 | }
47 |
48 | public boolean getMissing() {
49 | return missing;
50 | }
51 |
52 | public void setMissing(boolean missing) {
53 | this.missing = missing;
54 | }
55 |
56 | @Override
57 | public String toString() {
58 | return "WikiPage{" +
59 | "pageid=" + pageid +
60 | ", ns=" + ns +
61 | ", title='" + title + '\'' +
62 | ", extract='" + extract + '\'' +
63 | ", missing=" + missing +
64 | '}';
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/wikipedia/WikiQuery.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | import java.util.List;
4 |
5 | @SuppressWarnings("unused")
6 | public class WikiQuery {
7 | private List pages;
8 |
9 | public List getPages() {
10 | return pages;
11 | }
12 |
13 | public void setPages(List pages) {
14 | this.pages = pages;
15 | }
16 |
17 | @Override
18 | public String toString() {
19 | return "WikiQuery{" +
20 | "pages=" + pages +
21 | '}';
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/wikipedia/WikiResponse.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | @SuppressWarnings("unused")
4 | public class WikiResponse {
5 | private String batchcomplete;
6 | private WikiQuery query;
7 |
8 | public String getBatchcomplete() {
9 | return batchcomplete;
10 | }
11 |
12 | public void setBatchcomplete(String batchcomplete) {
13 | this.batchcomplete = batchcomplete;
14 | }
15 |
16 | public WikiQuery getQuery() {
17 | return query;
18 | }
19 |
20 | public void setQuery(WikiQuery query) {
21 | this.query = query;
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | return "WikiResponse{" +
27 | "batchcomplete=" + batchcomplete +
28 | ", query=" + query +
29 | '}';
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/kousenit/wikipedia/WikiUtil.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 |
6 | import java.io.IOException;
7 | import java.net.URI;
8 | import java.net.URLEncoder;
9 | import java.net.http.HttpClient;
10 | import java.net.http.HttpRequest;
11 | import java.net.http.HttpResponse;
12 | import java.nio.charset.StandardCharsets;
13 | import java.time.Duration;
14 | import java.util.Map;
15 | import java.util.stream.Collectors;
16 |
17 | public class WikiUtil {
18 | public static String getWikipediaExtract(String title) {
19 | String base = "https://en.wikipedia.org/w/api.php";
20 | Map params = Map.ofEntries(
21 | Map.entry("action", "query"),
22 | Map.entry("prop", "extracts"),
23 | Map.entry("format", "json"),
24 | Map.entry("exintro", "true"),
25 | Map.entry("explaintext", "1"),
26 | Map.entry("titles", URLEncoder.encode(title, StandardCharsets.UTF_8)),
27 | Map.entry("redirects", "1"),
28 | Map.entry("formatversion", "2")
29 | );
30 | String queryString = params.entrySet().stream()
31 | .map(Map.Entry::toString)
32 | .collect(Collectors.joining("&"));
33 | try {
34 | return getResponse(String.format("%s?%s", base, queryString));
35 | } catch (IOException | InterruptedException e) {
36 | throw new RuntimeException(e);
37 | }
38 | }
39 |
40 | private static String getResponse(String url) throws IOException, InterruptedException {
41 | HttpClient client = HttpClient.newHttpClient();
42 | HttpRequest request = HttpRequest.newBuilder()
43 | .uri(URI.create(url))
44 | .timeout(Duration.ofSeconds(2))
45 | .build();
46 | return parseResponse(client.send(request, HttpResponse.BodyHandlers.ofString()));
47 | }
48 |
49 | private static String parseResponse(HttpResponse response) throws JsonProcessingException {
50 | ObjectMapper mapper = new ObjectMapper();
51 | WikiResponse json = mapper.readValue(response.body(), WikiResponse.class);
52 | WikiPage page = json.getQuery().getPages().get(0);
53 | if (page.getExtract() == null) {
54 | throw new RuntimeException("Page not found");
55 | }
56 | return Map.of(page.getTitle(), page.getExtract()).toString();
57 | }
58 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/astro/AssignmentTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.*;
6 |
7 | class AssignmentTest {
8 |
9 | @Test
10 | void testConstructorAndGetters() {
11 | // Arrange
12 | String name = "Ellen Ripley";
13 | String craft = "Nostromo";
14 |
15 | // Act
16 | Assignment assignment = new Assignment(name, craft);
17 |
18 | // Assert
19 | assertEquals(name, assignment.getName());
20 | assertEquals(craft, assignment.getCraft());
21 | }
22 |
23 | @Test
24 | void testToString() {
25 | // Arrange
26 | String name = "Ellen Ripley";
27 | String craft = "Nostromo";
28 | Assignment assignment = new Assignment(name, craft);
29 |
30 | // Act
31 | String result = assignment.toString();
32 |
33 | // Assert
34 | assertTrue(result.contains(name));
35 | assertTrue(result.contains(craft));
36 | }
37 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/astro/AstroGatewayHttpClientTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.*;
6 |
7 | class AstroGatewayHttpClientTest {
8 | private final Gateway gateway = new AstroGatewayHttpClient();
9 |
10 | @Test
11 | void testDeserializeToRecords() {
12 | AstroResponse result = gateway.getResponse();
13 | result.getPeople().forEach(System.out::println);
14 | assertAll(
15 | () -> assertTrue(result.getNumber() >= 0),
16 | () -> assertEquals(result.getPeople().size(), result.getNumber())
17 | );
18 | }
19 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/astro/AstroGatewayRetrofitTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.*;
6 |
7 | class AstroGatewayRetrofitTest {
8 | private final Gateway gateway = new AstroGatewayRetrofit();
9 |
10 | @Test
11 | void testDeserializeToRecords() {
12 | AstroResponse result = gateway.getResponse();
13 | result.getPeople().forEach(System.out::println);
14 | assertAll(
15 | () -> assertTrue(result.getNumber() >= 0),
16 | () -> assertEquals(result.getPeople().size(), result.getNumber())
17 | );
18 | }
19 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/astro/AstroServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.extension.ExtendWith;
5 | import org.mockito.InjectMocks;
6 | import org.mockito.Mock;
7 | import org.mockito.junit.jupiter.MockitoExtension;
8 |
9 | import java.io.IOException;
10 | import java.util.Arrays;
11 | import java.util.Map;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
15 | import static org.junit.jupiter.api.Assertions.*;
16 | import static org.mockito.BDDMockito.*;
17 |
18 | @ExtendWith(MockitoExtension.class)
19 | class AstroServiceTest {
20 | private final AstroResponse mockAstroResponse =
21 | new AstroResponse(7, "Success", Arrays.asList(
22 | new Assignment("John Sheridan", "Babylon 5"),
23 | new Assignment("Susan Ivanova", "Babylon 5"),
24 | new Assignment("Beckett Mariner", "USS Cerritos"),
25 | new Assignment("Brad Boimler", "USS Cerritos"),
26 | new Assignment("Sam Rutherford", "USS Cerritos"),
27 | new Assignment("D'Vana Tendi", "USS Cerritos"),
28 | new Assignment("Ellen Ripley", "Nostromo")
29 | ));
30 |
31 | @Mock
32 | private Gateway gateway;
33 |
34 | @InjectMocks
35 | private AstroService service;
36 |
37 | @Test
38 | void testAstroData_usingInjectedMockGateway() {
39 | // Mock Gateway created and injected into AstroService using
40 | // @Mock and @InjectMock annotations
41 | //
42 | // Set the expectations on the mock
43 | when(gateway.getResponse())
44 | .thenReturn(mockAstroResponse);
45 |
46 | // Call the method under test
47 | Map astroData = service.getAstroData();
48 |
49 | // Check the results from the method under test (AssertJ)
50 | assertThat(astroData)
51 | .containsEntry("Babylon 5", 2L)
52 | .containsEntry("Nostromo", 1L)
53 | .containsEntry("USS Cerritos", 4L);
54 |
55 | // Verify the stubbed method was called
56 | verify(gateway).getResponse();
57 | // verify(gateway, times(1)).getResponse();
58 | }
59 |
60 | // Unit test with injected mock Gateway (uses annotations)
61 | @Test
62 | void testAstroData_usingInjectedMockGatewayBDD() {
63 | // Mock Gateway created and injected into AstroService using
64 | // @Mock and @InjectMock annotations
65 | //
66 | // Set the expectations on the mock
67 | given(gateway.getResponse())
68 | .willReturn(mockAstroResponse);
69 |
70 | // Call the method under test
71 | Map astroData = service.getAstroData();
72 |
73 | // Check the results from the method under test (AssertJ)
74 | assertThat(astroData)
75 | .containsEntry("Babylon 5", 2L)
76 | .containsEntry("Nostromo", 1L)
77 | .containsEntry("USS Cerritos", 4L);
78 |
79 | // Verify the stubbed method was called
80 | then(gateway).should().getResponse();
81 | }
82 |
83 | // Check network failure
84 | @Test
85 | void testAstroData_usingFailedGateway() {
86 | when(gateway.getResponse()).thenThrow(
87 | new RuntimeException(new IOException("Network problems")));
88 |
89 | // Check the exception (JUnit 5, which isn't bad)
90 | RuntimeException exception =
91 | assertThrows(RuntimeException.class, () -> service.getAstroData());
92 | Throwable cause = exception.getCause();
93 | assertAll(
94 | () -> assertEquals(IOException.class, cause.getClass()),
95 | () -> assertEquals("Network problems", cause.getMessage())
96 | );
97 |
98 | // Check the exception (AssertJ, which is way, way better :)
99 | assertThatExceptionOfType(RuntimeException.class)
100 | .isThrownBy(() -> service.getAstroData())
101 | .withCauseExactlyInstanceOf(IOException.class)
102 | .withMessageContaining("Network problems");
103 | }
104 |
105 | // Check network failure
106 | @Test
107 | void testAstroData_usingFailedGatewayBDD() {
108 | // given:
109 | given(gateway.getResponse()).willThrow(
110 | new RuntimeException(new IOException("Network problems")));
111 |
112 | // when:
113 | Exception exception = assertThrows(RuntimeException.class,
114 | () -> service.getAstroData());
115 |
116 | // then:
117 | Throwable cause = exception.getCause();
118 | assertAll(
119 | () -> assertEquals(IOException.class, cause.getClass()),
120 | () -> assertEquals("Network problems", cause.getMessage())
121 | );
122 |
123 | then(gateway).should().getResponse();
124 | }
125 |
126 | // Integration test -- no mocks
127 | @Test
128 | void testAstroData_usingRealGateway_withRetrofit() {
129 | // Create an instance of AstroService using the real Gateway
130 | service = new AstroService(new AstroGatewayRetrofit());
131 |
132 | // Call the method under test
133 | Map astroData = service.getAstroData();
134 |
135 | // Print the results and check that they are reasonable
136 | astroData.forEach((craft, number) -> {
137 | System.out.println(number + " astronauts aboard " + craft);
138 | assertAll(
139 | () -> assertThat(number).isPositive(),
140 | () -> assertThat(craft).isNotBlank()
141 | );
142 | });
143 | }
144 |
145 | // Integration test -- no mocks
146 | @Test
147 | @org.junit.jupiter.api.Disabled("API connection timeout - disabled to allow tests to pass")
148 | void testAstroData_usingRealGateway_withHttpClient() {
149 | // Create an instance of AstroService using the real Gateway
150 | service = new AstroService(new AstroGatewayHttpClient());
151 |
152 | // Call the method under test
153 | Map astroData = service.getAstroData();
154 |
155 | // Print the results and check that they are reasonable
156 | astroData.forEach((craft, number) -> {
157 | System.out.println(number + " astronauts aboard " + craft);
158 | assertAll(
159 | () -> assertThat(number).isPositive(),
160 | () -> assertThat(craft).isNotBlank()
161 | );
162 | });
163 | }
164 |
165 | // Own mock class -- FakeGateway
166 | @Test
167 | void testAstroData_usingOwnMockGateway() {
168 | // Create the service using the mock Gateway
169 | service = new AstroService(new FakeGateway());
170 |
171 | // Call the method under test
172 | Map astroData = service.getAstroData();
173 |
174 | // Check the results from the method under test
175 | assertThat(astroData)
176 | .containsOnlyKeys("USS Voyager", "Jupiter 2",
177 | "Babylon 5", "Rocinante", "Nostromo")
178 | .containsEntry("USS Voyager", 2L)
179 | .containsEntry("Jupiter 2", 1L)
180 | .containsEntry("Babylon 5", 1L)
181 | .containsEntry("Rocinante", 2L)
182 | .containsEntry("Nostromo", 1L);
183 | }
184 |
185 | // Unit test with mock Gateway using mock(Gateway.class)
186 | @SuppressWarnings("unchecked")
187 | @Test
188 | void testAstroData_usingMockGateway() {
189 | // 1. Create a mock Gateway
190 | Gateway mockGateway = mock(Gateway.class);
191 |
192 | // 2. Set expectations on the mock Gateway
193 | when(mockGateway.getResponse())
194 | .thenReturn(mockAstroResponse);
195 |
196 | // 3. Create an instance of AstroService using the mock Gateway
197 | AstroService service = new AstroService(mockGateway);
198 |
199 | // 4. Call the method under test
200 | Map astroData = service.getAstroData();
201 |
202 | // 5. Check the results from the method under test
203 | assertThat(astroData)
204 | .containsEntry("Babylon 5", 2L)
205 | .containsEntry("USS Cerritos", 4L)
206 | .containsEntry("Nostromo", 1L)
207 | .hasSize(3);
208 |
209 | // 6. Verify that the mock Gateway method was called
210 | verify(mockGateway).getResponse();
211 | }
212 |
213 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/astro/FakeGateway.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.astro;
2 |
3 | import java.util.List;
4 |
5 | public class FakeGateway implements Gateway {
6 | @Override
7 | public AstroResponse getResponse() {
8 | return new AstroResponse(7, "Success",
9 | List.of(new Assignment("Kathryn Janeway", "USS Voyager"),
10 | new Assignment("Seven of Nine", "USS Voyager"),
11 | new Assignment("Will Robinson", "Jupiter 2"),
12 | new Assignment("Lennier", "Babylon 5"),
13 | new Assignment("James Holden", "Rocinante"),
14 | new Assignment("Naomi Negata", "Rocinante"),
15 | new Assignment("Ellen Ripley", "Nostromo")));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/hr/DefaultTranslationServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.extension.ExtendWith;
5 | import org.mockito.InjectMocks;
6 | import org.mockito.junit.jupiter.MockitoExtension;
7 |
8 | import static org.junit.jupiter.api.Assertions.assertEquals;
9 |
10 | @ExtendWith(MockitoExtension.class)
11 | class DefaultTranslationServiceTest {
12 |
13 | @InjectMocks
14 | private DefaultTranslationService service;
15 |
16 | @Test
17 | void testTranslateWithoutParameters() {
18 | // Arrange
19 | String text = "Hello, World!";
20 |
21 | // Act
22 | String result = service.translate(text);
23 |
24 | // Assert
25 | assertEquals(text, result, "Should return the original text unchanged");
26 | }
27 |
28 | @Test
29 | void testTranslateWithParameters() {
30 | // Arrange
31 | String text = "Hello, World!";
32 | String sourceLanguage = "en";
33 | String targetLanguage = "en";
34 |
35 | // Act
36 | String result = service.translate(text, sourceLanguage, targetLanguage);
37 |
38 | // Assert
39 | assertEquals(text, result, "Should return the original text unchanged");
40 | }
41 |
42 | @Test
43 | void testTranslateWithDifferentLanguages() {
44 | // Arrange
45 | String text = "Hello, World!";
46 | String sourceLanguage = "en";
47 | String targetLanguage = "fr";
48 |
49 | // Act
50 | String result = service.translate(text, sourceLanguage, targetLanguage);
51 |
52 | // Assert
53 | // The implementation always passes "en" to both source and target
54 | assertEquals(text, result, "Should return the original text unchanged regardless of requested languages");
55 | }
56 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/hr/HelloMockitoTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import org.junit.jupiter.api.DisplayName;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.extension.ExtendWith;
6 | import org.mockito.InOrder;
7 | import org.mockito.InjectMocks;
8 | import org.mockito.Mock;
9 | import org.mockito.MockedConstruction;
10 | import org.mockito.junit.jupiter.MockitoExtension;
11 |
12 | import java.time.LocalDate;
13 | import java.util.Optional;
14 |
15 | import static org.assertj.core.api.Assertions.assertThat;
16 | import static org.junit.jupiter.api.Assertions.assertEquals;
17 | import static org.mockito.Mockito.*;
18 | import static org.mockito.AdditionalAnswers.returnsFirstArg;
19 |
20 | @ExtendWith(MockitoExtension.class)
21 | class HelloMockitoTest {
22 | @Mock
23 | private PersonRepository repository;
24 |
25 | @Mock
26 | private TranslationService translationService;
27 |
28 | @InjectMocks
29 | private HelloMockito helloMockito;
30 |
31 | @Test
32 | @DisplayName("Greet Admiral Hopper")
33 | void greetForPersonThatExists() {
34 | // Set the expectations on the dependencies
35 | when(repository.findById(anyInt()))
36 | .thenReturn(Optional.of(new Person(1, "Grace", "Hopper", LocalDate.now())));
37 | when(translationService.translate(
38 | "Hello, Grace, from Mockito!", "en", "en"))
39 | .thenReturn("Hello, Grace, from Mockito!");
40 |
41 | // Test the greet method
42 | String greeting = helloMockito.greet(1, "en", "en");
43 | assertEquals("Hello, Grace, from Mockito!", greeting);
44 |
45 | // Verify that the dependencies were called as expected
46 | InOrder inOrder = inOrder(repository, translationService);
47 | inOrder.verify(repository)
48 | .findById(anyInt());
49 | inOrder.verify(translationService)
50 | .translate(anyString(), eq("en"), eq("en"));
51 | }
52 |
53 | @Test
54 | @DisplayName("Greet a person not in the database")
55 | void greetForPersonThatDoesNotExist() {
56 | when(repository.findById(anyInt()))
57 | .thenReturn(Optional.empty());
58 | when(translationService.translate(
59 | "Hello, World, from Mockito!", "en", "en"))
60 | .thenReturn("Hello, World, from Mockito!");
61 |
62 | String greeting = helloMockito.greet(100, "en", "en");
63 | assertEquals("Hello, World, from Mockito!", greeting);
64 |
65 | InOrder inOrder = inOrder(repository, translationService);
66 | inOrder.verify(repository)
67 | .findById(anyInt());
68 | inOrder.verify(translationService)
69 | .translate(anyString(), eq("en"), eq("en"));
70 | }
71 |
72 | @Test
73 | void greetWithDefaultTranslator() {
74 | PersonRepository mockRepo = mock(PersonRepository.class);
75 | when(mockRepo.findById(anyInt()))
76 | .thenReturn(Optional.of(new Person(1, "Grace", "Hopper", LocalDate.now())));
77 | HelloMockito helloMockito = new HelloMockito(mockRepo);
78 | String greeting = helloMockito.greet(1, "en", "en");
79 | assertThat(greeting).isEqualTo("Hello, Grace, from Mockito!");
80 | }
81 |
82 | @Test
83 | void greetWithMockedConstructor() {
84 | // Mock for repo (needed for HelloMockito constructor)
85 | PersonRepository mockRepo = mock(PersonRepository.class);
86 | when(mockRepo.findById(anyInt()))
87 | .thenReturn(Optional.of(new Person(1, "Grace", "Hopper", LocalDate.now())));
88 |
89 | // Mock for translator (instantiated inside HelloMockito constructor)
90 | try (MockedConstruction ignored =
91 | mockConstruction(DefaultTranslationService.class,
92 | (mock, context) -> when(mock.translate(anyString(), anyString(), anyString()))
93 | .thenAnswer(invocation -> invocation.getArgument(0) + " (translated)"))) {
94 |
95 | // Instantiate HelloMockito with mocked repo and locally instantiated translator
96 | HelloMockito hello = new HelloMockito(mockRepo);
97 | String greeting = hello.greet(1, "en", "en");
98 | assertThat(greeting).isEqualTo("Hello, Grace, from Mockito! (translated)");
99 |
100 | // Any instantiation of DefaultTranslationService will return the mocked instance
101 | DefaultTranslationService translator = new DefaultTranslationService();
102 | String translate = translator.translate("What up?", "en", "en");
103 | assertThat(translate).isEqualTo("What up? (translated)");
104 | }
105 | }
106 |
107 | @Test
108 | void greetWithMockedConstructorWithAnswer() {
109 | // Mock for repo (needed for HelloMockito constructor)
110 | PersonRepository mockRepo = mock(PersonRepository.class);
111 | when(mockRepo.findById(anyInt()))
112 | .thenReturn(Optional.of(new Person(1, "Grace", "Hopper", LocalDate.now())));
113 |
114 | // Mock for translator (instantiated inside HelloMockito constructor)
115 | try (MockedConstruction ignored =
116 | mockConstructionWithAnswer(DefaultTranslationService.class,
117 | invocation -> invocation.getArgument(0) + " (translated)",
118 | invocation -> invocation.getArgument(0) + " (translated again)")) {
119 |
120 | // Instantiate HelloMockito with mocked repo and locally instantiated translator
121 | HelloMockito hello = new HelloMockito(mockRepo);
122 | String greeting = hello.greet(1, "en", "en");
123 | assertThat(greeting).isEqualTo("Hello, Grace, from Mockito! (translated)");
124 | }
125 | }
126 |
127 | @Test
128 | void testGetterAndSetter() {
129 | assertThat(helloMockito.getGreeting()).isNotNull();
130 | assertThat(helloMockito.getGreeting()).isEqualTo("Hello, %s, from Mockito!");
131 |
132 | helloMockito.setGreeting("Hi there, %s, from Mockito!");
133 | assertThat(helloMockito.getGreeting()).isEqualTo("Hi there, %s, from Mockito!");
134 | }
135 |
136 | @Test
137 | @DisplayName("Integration test without mocks")
138 | void helloMockitoWithExplicitStubs() {
139 | PersonRepository personRepo = new InMemoryPersonRepository();
140 |
141 | helloMockito = new HelloMockito(
142 | personRepo,
143 | new DefaultTranslationService()
144 | );
145 |
146 | // Save a person
147 | Person person = new Person(1, "Grace", "Hopper", LocalDate.now());
148 | personRepo.save(person);
149 |
150 | // Greet a user that exists
151 | String greeting = helloMockito.greet(1, "en", "en");
152 | assertThat(greeting).isEqualTo("Hello, Grace, from Mockito!");
153 |
154 | // Greet a user that does not exist
155 | greeting = helloMockito.greet(100, "en", "en");
156 | assertThat(greeting).isEqualTo("Hello, World, from Mockito!");
157 | }
158 |
159 | @Test
160 | @DisplayName("Greet Admiral Hopper")
161 | void greetAPersonUsingAnswers() {
162 | // Set the expectations on the dependencies
163 | when(repository.findById(anyInt()))
164 | .thenReturn(Optional.of(new Person(1, "Grace", "Hopper", LocalDate.now())));
165 | when(translationService.translate(
166 | anyString(), eq("en"), eq("en")))
167 | .thenAnswer(returnsFirstArg());
168 |
169 | // Test the greet method
170 | String greeting = helloMockito.greet(1, "en", "en");
171 | assertEquals("Hello, Grace, from Mockito!", greeting);
172 |
173 | // Verify that the dependencies were called as expected
174 | verify(repository)
175 | .findById(anyInt());
176 | verify(translationService)
177 | // gives an error: if one arg is an argument matcher, they all have to be
178 | // .translate(anyString(), "en", "en");
179 | .translate(anyString(), eq("en"), eq("en"));
180 | }
181 |
182 | @Test
183 | void greetPersonWithSpecifiedLanguages() {
184 | Person hopper = new Person(1, "Grace", "Hopper",
185 | LocalDate.of(1906, 12, 9));
186 |
187 | TranslationService mockTranslator = mock(TranslationService.class);
188 | when(mockTranslator.translate(anyString(), anyString(), anyString()))
189 | .thenReturn(String.format("Hello, %s, from Mockito", hopper.getFirst())
190 | + " (translated)");
191 |
192 | HelloMockito helloMockito = new HelloMockito(mockTranslator);
193 | String greeting = helloMockito.greet(hopper, "en", "en");
194 | assertThat(greeting).isEqualTo("Hello, Grace, from Mockito (translated)");
195 | }
196 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/hr/InMemoryPersonRepositoryTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.time.LocalDate;
7 | import java.time.Month;
8 | import java.util.List;
9 | import java.util.Optional;
10 |
11 | import static org.junit.jupiter.api.Assertions.*;
12 |
13 | public class InMemoryPersonRepositoryTest {
14 | private InMemoryPersonRepository repository;
15 | private final Person person1 = new Person(1, "Grace", "Hopper",
16 | LocalDate.of(1906, Month.DECEMBER, 9));
17 | private final Person person2 = new Person(2, "Ada", "Lovelace",
18 | LocalDate.of(1815, Month.DECEMBER, 10));
19 | private final Person person3 = new Person(3, "Barbara", "Liskov",
20 | LocalDate.of(1939, Month.NOVEMBER, 7));
21 |
22 | @BeforeEach
23 | void setUp() {
24 | repository = new InMemoryPersonRepository();
25 | }
26 |
27 | @Test
28 | void testSave() {
29 | Person savedPerson = repository.save(person1);
30 | assertEquals(person1, savedPerson);
31 | assertEquals(1, repository.count());
32 | }
33 |
34 | @Test
35 | void testFindById_whenExists() {
36 | repository.save(person1);
37 | repository.save(person2);
38 |
39 | Optional foundPerson = repository.findById(1);
40 | assertTrue(foundPerson.isPresent());
41 | assertEquals(person1, foundPerson.get());
42 | }
43 |
44 | @Test
45 | void testFindById_whenDoesNotExist() {
46 | repository.save(person1);
47 |
48 | Optional foundPerson = repository.findById(999);
49 | assertFalse(foundPerson.isPresent());
50 | }
51 |
52 | @Test
53 | void testFindAll() {
54 | repository.save(person1);
55 | repository.save(person2);
56 | repository.save(person3);
57 |
58 | List people = repository.findAll();
59 | assertEquals(3, people.size());
60 | assertTrue(people.contains(person1));
61 | assertTrue(people.contains(person2));
62 | assertTrue(people.contains(person3));
63 | }
64 |
65 | @Test
66 | void testCount() {
67 | assertEquals(0, repository.count());
68 |
69 | repository.save(person1);
70 | assertEquals(1, repository.count());
71 |
72 | repository.save(person2);
73 | assertEquals(2, repository.count());
74 | }
75 |
76 | @Test
77 | void testDelete() {
78 | repository.save(person1);
79 | repository.save(person2);
80 | assertEquals(2, repository.count());
81 |
82 | repository.delete(person1);
83 | assertEquals(1, repository.count());
84 | assertFalse(repository.findById(person1.getId()).isPresent());
85 | assertTrue(repository.findById(person2.getId()).isPresent());
86 | }
87 |
88 | @Test
89 | void testDelete_whenPersonNotInRepository() {
90 | repository.save(person1);
91 | repository.save(person2);
92 | assertEquals(2, repository.count());
93 |
94 | repository.delete(person3);
95 | assertEquals(2, repository.count());
96 | }
97 |
98 | @Test
99 | void testThreadSafety() throws InterruptedException {
100 | // This test verifies the synchronized blocks work correctly
101 | final int personCount = 100;
102 |
103 | // Create and start multiple threads that save persons concurrently
104 | Thread thread1 = new Thread(() -> {
105 | for (int i = 0; i < personCount; i++) {
106 | repository.save(new Person(i, "Thread1", "Person" + i, LocalDate.now()));
107 | }
108 | });
109 |
110 | Thread thread2 = new Thread(() -> {
111 | for (int i = personCount; i < personCount * 2; i++) {
112 | repository.save(new Person(i, "Thread2", "Person" + i, LocalDate.now()));
113 | }
114 | });
115 |
116 | thread1.start();
117 | thread2.start();
118 |
119 | // Wait for both threads to complete
120 | thread1.join();
121 | thread2.join();
122 |
123 | // Verify that all persons were saved correctly
124 | assertEquals(personCount * 2, repository.count());
125 | }
126 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/hr/PersonServiceBDDTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.extension.ExtendWith;
5 | import org.mockito.InjectMocks;
6 | import org.mockito.Mock;
7 | import org.mockito.junit.jupiter.MockitoExtension;
8 |
9 | import java.time.LocalDate;
10 | import java.time.Month;
11 | import java.time.format.DateTimeParseException;
12 | import java.util.Arrays;
13 | import java.util.List;
14 |
15 | import static org.assertj.core.api.Assertions.assertThat;
16 | import static org.junit.jupiter.api.Assertions.assertEquals;
17 | import static org.junit.jupiter.api.Assertions.assertThrows;
18 | import static org.mockito.BDDMockito.*;
19 |
20 | @ExtendWith(MockitoExtension.class)
21 | public class PersonServiceBDDTest {
22 | @Mock
23 | private PersonRepository repository;
24 |
25 | @InjectMocks
26 | private PersonService service;
27 |
28 | private final List people = Arrays.asList(
29 | new Person(1, "Grace", "Hopper",
30 | LocalDate.of(1906, Month.DECEMBER, 9)),
31 | new Person(2, "Ada", "Lovelace",
32 | LocalDate.of(1815, Month.DECEMBER, 10)),
33 | new Person(3, "Adele", "Goldberg",
34 | LocalDate.of(1945, Month.JULY, 7)),
35 | new Person(14, "Anita", "Borg",
36 | LocalDate.of(1949, Month.JANUARY, 17)),
37 | new Person(5, "Barbara", "Liskov",
38 | LocalDate.of(1939, Month.NOVEMBER, 7)));
39 |
40 | @Test
41 | public void findMaxId() {
42 | given(repository.findAll()).willReturn(people);
43 | assertThat(service.getHighestId()).isEqualTo(14);
44 | }
45 |
46 | @Test
47 | public void getLastNames() {
48 | given(repository.findAll()).willReturn(people);
49 | assertThat(service.getLastNames())
50 | .containsExactly("Hopper", "Lovelace", "Goldberg", "Borg", "Liskov");
51 | }
52 |
53 | @Test
54 | public void getTotalPeople() {
55 | given(repository.count()).willReturn((long) people.size());
56 | assertEquals(service.getTotalPeople(), people.size());
57 | }
58 |
59 | @Test
60 | public void saveAllPeople() {
61 | given(repository.save(any(Person.class)))
62 | .willReturn(people.get(0),
63 | people.get(1),
64 | people.get(2),
65 | people.get(3),
66 | people.get(4));
67 |
68 | List ids = service.savePeople(
69 | people.toArray(Person[]::new));
70 | assertThat(ids).containsExactly(1, 2, 3, 14, 5);
71 |
72 | then(repository)
73 | .should(times(5))
74 | .save(any(Person.class));
75 | then(repository).shouldHaveNoMoreInteractions();
76 | }
77 |
78 | @Test
79 | public void saveAllPeopleUsingAnswer() {
80 | given(repository.save(any(Person.class)))
81 | .willAnswer(invocation -> invocation.getArgument(0));
82 |
83 | List ids = service.savePeople(
84 | people.toArray(Person[]::new));
85 | assertThat(ids).containsExactly(1, 2, 3, 14, 5);
86 |
87 | then(repository)
88 | .should(times(5))
89 | .save(any(Person.class));
90 | then(repository).shouldHaveNoMoreInteractions();
91 | }
92 |
93 | @Test
94 | public void useAnswer() {
95 | given(repository.save(any(Person.class)))
96 | .will(invocation -> invocation.getArgument(0));
97 |
98 | List ids = service.savePeople(people.toArray(Person[]::new));
99 |
100 | assertThat(ids).containsExactly(1, 2, 3, 14, 5);
101 | }
102 |
103 | @Test
104 | public void createPersonWithBadDateString() {
105 | DateTimeParseException exception = assertThrows(DateTimeParseException.class,
106 | () -> service.createPerson(1, "Grace", "Hopper", "12/09/1906"));
107 | assertThat(exception.getMessage()).contains("could not be parsed");
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/hr/PersonServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import org.junit.jupiter.api.Disabled;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.extension.ExtendWith;
6 | import org.mockito.ArgumentCaptor;
7 | import org.mockito.Captor;
8 | import org.mockito.InjectMocks;
9 | import org.mockito.Mock;
10 | import org.mockito.invocation.InvocationOnMock;
11 | import org.mockito.junit.jupiter.MockitoExtension;
12 | import org.mockito.stubbing.Answer;
13 |
14 | import java.time.LocalDate;
15 | import java.time.Month;
16 | import java.util.Arrays;
17 | import java.util.List;
18 | import java.util.Map;
19 | import java.util.Optional;
20 | import java.util.stream.Collectors;
21 |
22 | import static org.assertj.core.api.Assertions.assertThat;
23 | import static org.junit.jupiter.api.Assertions.*;
24 | import static org.mockito.AdditionalAnswers.returnsFirstArg;
25 | import static org.mockito.BDDMockito.given;
26 | import static org.mockito.BDDMockito.then;
27 | import static org.mockito.Mockito.*;
28 |
29 | @ExtendWith(MockitoExtension.class)
30 | public class PersonServiceTest {
31 |
32 | @Mock
33 | private PersonRepository repository;
34 |
35 | @InjectMocks
36 | private PersonService service;
37 |
38 | @Captor
39 | private ArgumentCaptor personArg;
40 |
41 | private final List people = List.of(
42 | new Person(1, "Grace", "Hopper", LocalDate.of(1906, Month.DECEMBER, 9)),
43 | new Person(2, "Ada", "Lovelace", LocalDate.of(1815, Month.DECEMBER, 10)),
44 | new Person(3, "Adele", "Goldberg", LocalDate.of(1945, Month.JULY, 7)),
45 | new Person(14, "Anita", "Borg", LocalDate.of(1949, Month.JANUARY, 17)),
46 | new Person(5, "Barbara", "Liskov", LocalDate.of(1939, Month.NOVEMBER, 7)));
47 |
48 | private final Map peopleMap = people.stream()
49 | .collect(Collectors.toMap(Person::getId, p -> p));
50 |
51 | // Can't be done because JUnit 5 extension is _strict_ and
52 | // many of these tests don't call repository.findAll()
53 | // @BeforeEach
54 | // void setUp() {
55 | // when(repository.findAll()).thenReturn(people);
56 | // }
57 |
58 | @Test
59 | public void findMaxId() {
60 | when(repository.findAll()).thenReturn(people);
61 |
62 | assertThat(service.getHighestId()).isEqualTo(14);
63 |
64 | verify(repository).findAll();
65 | }
66 |
67 | @Test
68 | public void findMaxId_BDD() {
69 | given(repository.findAll()).willReturn(people);
70 |
71 | assertThat(service.getHighestId()).isEqualTo(14);
72 |
73 | then(repository).should()
74 | .findAll();
75 | // then(repository).should(times(1)).findAll();
76 | }
77 |
78 | @Test
79 | void defaultImplementations() {
80 | PersonRepository mockRepo = mock(PersonRepository.class);
81 | assertAll(
82 | () -> assertNull(mockRepo.save(any(Person.class))),
83 | () -> assertTrue(mockRepo.findById(anyInt())
84 | .isEmpty()),
85 | () -> assertTrue(mockRepo.findAll()
86 | .isEmpty()),
87 | () -> assertEquals(0, mockRepo.count())
88 | );
89 | }
90 |
91 | @Test
92 | void getLastNames_usingMockMethod() {
93 | PersonRepository mockRepo = mock(PersonRepository.class);
94 | when(mockRepo.findAll()).thenReturn(people);
95 |
96 | PersonService personService = new PersonService(mockRepo);
97 |
98 | List lastNames = personService.getLastNames();
99 |
100 | assertThat(lastNames)
101 | .contains("Borg", "Goldberg", "Hopper", "Liskov", "Lovelace");
102 | verify(mockRepo).findAll();
103 | }
104 |
105 | @Test
106 | public void getLastNames_usingAnnotations() {
107 | when(repository.findAll()).thenReturn(people);
108 |
109 | assertThat(service.getLastNames())
110 | .contains("Borg", "Goldberg", "Hopper", "Liskov", "Lovelace");
111 |
112 | verify(repository).findAll();
113 | }
114 |
115 | @Test
116 | public void getTotalPeople() {
117 | when(repository.count())
118 | .thenReturn((long) people.size());
119 | assertEquals(people.size(), service.getTotalPeople());
120 | }
121 |
122 | @Test
123 | public void saveAllPeople() {
124 | // set expectations on the mock repository
125 | when(repository.save(any(Person.class)))
126 | .thenReturn(people.get(0),
127 | people.get(1),
128 | people.get(2),
129 | people.get(3),
130 | people.get(4));
131 |
132 | // test the savePeople method
133 | List ids = service.savePeople(people.toArray(Person[]::new));
134 |
135 | // check the results
136 | List actuals = people.stream()
137 | .map(Person::getId)
138 | .collect(Collectors.toList());
139 | assertThat(ids).containsExactlyElementsOf(actuals);
140 |
141 | // verify the interaction between the service and the mock
142 | verify(repository, times(people.size())).save(any(Person.class));
143 | verify(repository, never()).delete(any(Person.class));
144 | }
145 |
146 | @SuppressWarnings("Convert2Lambda")
147 | @Test
148 | public void saveAllPeople_usingAnswer_anonInnerClass() {
149 | // Anonymous inner class
150 | when(repository.save(any(Person.class)))
151 | .thenAnswer(new Answer() {
152 | @Override
153 | public Person answer(InvocationOnMock invocation) {
154 | return invocation.getArgument(0);
155 | }
156 | });
157 |
158 | // test the savePeople method
159 | List ids = service.savePeople(people.toArray(Person[]::new));
160 |
161 | // check the results
162 | List actuals = people.stream()
163 | .map(Person::getId)
164 | .collect(Collectors.toList());
165 | assertThat(ids).containsExactlyElementsOf(actuals);
166 | }
167 |
168 | @Test
169 | public void saveAllPeople_usingAnswer_lambdaExpression() {
170 | // Lambda expression implementation of Answer
171 | when(repository.save(any(Person.class)))
172 | .thenAnswer(invocation -> invocation.getArgument(0));
173 |
174 | // test the savePeople method
175 | List ids = service.savePeople(people.toArray(Person[]::new));
176 |
177 | // check the results
178 | List actuals = people.stream()
179 | .map(Person::getId)
180 | .collect(Collectors.toList());
181 | assertThat(ids).containsExactlyElementsOf(actuals);
182 | }
183 |
184 | @Test
185 | public void saveAllPeople_usingAdditionalAnswers() {
186 | // set the expectations on the mock
187 | when(repository.save(any(Person.class)))
188 | .thenAnswer(returnsFirstArg());
189 |
190 | // invoke the test method
191 | List ids = service.savePeople(people.toArray(Person[]::new));
192 |
193 | // check the results
194 | List actuals = people.stream()
195 | .map(Person::getId)
196 | .collect(Collectors.toList());
197 | assertThat(ids).containsExactlyElementsOf(actuals);
198 | }
199 |
200 | @Test
201 | public void savePersonThrowsException() {
202 | when(repository.save(any(Person.class)))
203 | .thenThrow(RuntimeException.class);
204 |
205 | assertThrows(RuntimeException.class, () -> service.savePeople(people.get(0)));
206 | }
207 |
208 | @Test
209 | public void createPerson() {
210 | when(repository.save(any(Person.class)))
211 | .thenAnswer(invocation -> invocation.getArgument(0));
212 |
213 | Person hopper = people.get(0);
214 | Person person = service.createPerson(
215 | hopper.getId(),
216 | hopper.getFirst(),
217 | hopper.getLast(),
218 | hopper.getDob());
219 |
220 | verify(repository).save(personArg.capture());
221 |
222 | assertEquals(personArg.getValue(), hopper);
223 | assertEquals(hopper, person);
224 | }
225 |
226 | @Test
227 | public void createPersonUsingDateString() {
228 | Person hopper = people.get(0);
229 |
230 | when(repository.save(hopper)).thenReturn(hopper); // generalize this with an answer
231 | Person actual = service.createPerson(1, "Grace", "Hopper", "1906-12-09");
232 |
233 | verify(repository).save(personArg.capture());
234 | assertThat(personArg.getValue()).isEqualTo(hopper);
235 | assertThat(actual).isEqualTo(hopper);
236 | }
237 |
238 | @Test
239 | public void deleteAll() {
240 | when(repository.findAll()).thenReturn(people);
241 |
242 | doNothing().when(repository)
243 | .delete(any(Person.class));
244 |
245 | service.deleteAll();
246 |
247 | verify(repository, times(5)).delete(any(Person.class));
248 | }
249 |
250 | @SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
251 | @Test
252 | public void deleteAllWithNulls() {
253 | when(repository.findAll()).thenReturn(
254 | Arrays.asList((Person) null));
255 |
256 | //when(repository.delete(null)).thenThrow(RuntimeException.class);
257 | doThrow(RuntimeException.class).when(repository)
258 | .delete(null);
259 |
260 | assertThrows(RuntimeException.class, () -> service.deleteAll());
261 |
262 | verify(repository).delete(null);
263 | }
264 |
265 | @Test
266 | @Disabled("Do not use argThat with integers")
267 | public void findByIdThatDoesNotExist_argThat() {
268 | // More specific, custom matcher
269 | when(repository.findById(argThat(id -> id > 14)))
270 | .thenReturn(Optional.empty());
271 |
272 | List personList = service.findByIds(999);
273 | assertTrue(personList.isEmpty());
274 |
275 | verify(repository).findById(anyInt());
276 | }
277 |
278 |
279 | @Test
280 | public void findByIdsThatDoNotExist_intThat() {
281 | // More specific, custom matcher
282 | when(repository.findById(intThat(id -> id > 14)))
283 | .thenReturn(Optional.empty());
284 |
285 | List personList = service.findByIds(15, 42, 78, 999);
286 | assertTrue(personList.isEmpty());
287 |
288 | verify(repository, times(4)).findById(anyInt());
289 | }
290 |
291 | @Test
292 | public void findByIdsThatDoExist() {
293 | int maxId = peopleMap.keySet()
294 | .stream()
295 | .max(Integer::compareTo)
296 | .orElse(0);
297 | when(repository.findById(intThat(id -> id <= maxId)))
298 | .thenAnswer(invocation -> {
299 | int id = invocation.getArgument(0);
300 | return Optional.ofNullable(peopleMap.get(id));
301 | });
302 |
303 | List personList = service.findByIds(1, 3, 5, maxId);
304 | assertThat(personList).containsExactlyElementsOf(
305 | List.of(peopleMap.get(1), peopleMap.get(3),
306 | peopleMap.get(5), peopleMap.get(maxId)));
307 | }
308 |
309 | @Test
310 | void findByIds_explicitWhens() {
311 | when(repository.findById(0))
312 | .thenReturn(Optional.of(people.get(0)));
313 | when(repository.findById(1))
314 | .thenReturn(Optional.of(people.get(1)));
315 | when(repository.findById(2))
316 | .thenReturn(Optional.of(people.get(2)));
317 | when(repository.findById(3))
318 | .thenReturn(Optional.of(people.get(3)));
319 | when(repository.findById(4))
320 | .thenReturn(Optional.of(people.get(4)));
321 | when(repository.findById(5))
322 | .thenReturn(Optional.empty());
323 |
324 | List personList = service.findByIds(0, 1, 2, 3, 4, 5);
325 | assertThat(personList).containsExactlyElementsOf(people);
326 | }
327 |
328 | @SuppressWarnings("unchecked")
329 | @Test
330 | void findByIds_thenReturnWithMultipleArgs() {
331 | when(repository.findById(anyInt())).thenReturn(
332 | Optional.of(people.get(0)),
333 | Optional.of(people.get(1)),
334 | Optional.of(people.get(2)),
335 | Optional.of(people.get(3)),
336 | Optional.of(people.get(4)),
337 | Optional.empty());
338 |
339 | List personList = service.findByIds(0, 1, 2, 3, 4, 5);
340 | assertThat(personList).isEqualTo(people);
341 | }
342 |
343 | @Test
344 | void testInMemoryPersonRepository() {
345 | PersonRepository personRepo = new InMemoryPersonRepository();
346 | PersonService personService = new PersonService(personRepo);
347 |
348 | personService.savePeople(people.toArray(Person[]::new));
349 | assertThat(personRepo.findAll()).isEqualTo(people);
350 | }
351 |
352 | @Test
353 | void testMockOfFinalMethod() {
354 | PersonRepository personRepo = mock(InMemoryPersonRepository.class);
355 |
356 | // Set expectations on the mock
357 | when(personRepo.save(any(Person.class)))
358 | .thenAnswer(invocation -> invocation.getArgument(0));
359 |
360 | // Inject the mock into the class under test
361 | PersonService personService = new PersonService(personRepo);
362 |
363 | // Test the savePeople method
364 | List ids = personService.savePeople(people.toArray(Person[]::new));
365 | assertThat(ids).containsExactly(1, 2, 3, 14, 5);
366 |
367 | // Verify the save method in the mock was called as expected
368 | verify(personRepo, times(5)).save(any(Person.class));
369 | }
370 |
371 | @Test
372 | void spyOnRepository() {
373 | PersonRepository personRepo = spy(new InMemoryPersonRepository());
374 | PersonService personService = new PersonService(personRepo);
375 |
376 | personService.savePeople(people.toArray(Person[]::new));
377 | assertThat(personRepo.findAll()).isEqualTo(people);
378 |
379 | verify(personRepo, times(people.size())).save(any(Person.class));
380 | }
381 |
382 | @Test
383 | void asyncSavePerson() {
384 | Person firstPerson = people.get(0);
385 | long delay = 100;
386 |
387 | // Call the method under test
388 | service.asyncSavePerson(firstPerson, delay);
389 |
390 | // Verify that the save method was called on the repo with the person
391 | verify(repository, timeout(2 * delay)).save(firstPerson);
392 | }
393 |
394 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/hr/PersonTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.hr;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.time.LocalDate;
6 | import java.time.Month;
7 |
8 | import static org.junit.jupiter.api.Assertions.*;
9 |
10 | public class PersonTest {
11 | private final Person person1 = new Person(1, "Grace", "Hopper",
12 | LocalDate.of(1906, Month.DECEMBER, 9));
13 | private final Person person1Copy = new Person(1, "Grace", "Hopper",
14 | LocalDate.of(1906, Month.DECEMBER, 9));
15 | private final Person person2 = new Person(2, "Ada", "Lovelace",
16 | LocalDate.of(1815, Month.DECEMBER, 10));
17 | private final Person personNullId = new Person(null, "Grace", "Hopper",
18 | LocalDate.of(1906, Month.DECEMBER, 9));
19 | private final Person personNullFirst = new Person(1, null, "Hopper",
20 | LocalDate.of(1906, Month.DECEMBER, 9));
21 | private final Person personNullLast = new Person(1, "Grace", null,
22 | LocalDate.of(1906, Month.DECEMBER, 9));
23 | private final Person personNullDob = new Person(1, "Grace", "Hopper", null);
24 |
25 | @Test
26 | void testEqualsWithSameReference() {
27 | // Test case where object equals itself (same reference)
28 | assertTrue(person1.equals(person1));
29 | }
30 |
31 | @Test
32 | void testEqualsWithNull() {
33 | // Test case with null
34 | assertFalse(person1.equals(null));
35 | }
36 |
37 | @Test
38 | void testEqualsWithDifferentClass() {
39 | // Test case with different class
40 | assertFalse(person1.equals("Not a Person"));
41 | }
42 |
43 | @Test
44 | void testEqualsWithEqualObjects() {
45 | // Test case with equal objects
46 | assertTrue(person1.equals(person1Copy));
47 | assertTrue(person1Copy.equals(person1));
48 | }
49 |
50 | @Test
51 | void testEqualsWithDifferentObjects() {
52 | // Test case with different objects
53 | assertFalse(person1.equals(person2));
54 | assertFalse(person2.equals(person1));
55 | }
56 |
57 | @Test
58 | void testEqualsWithNullFields() {
59 | // Test cases with null fields
60 | assertFalse(person1.equals(personNullId));
61 | assertFalse(personNullId.equals(person1));
62 |
63 | assertFalse(person1.equals(personNullFirst));
64 | assertFalse(personNullFirst.equals(person1));
65 |
66 | assertFalse(person1.equals(personNullLast));
67 | assertFalse(personNullLast.equals(person1));
68 |
69 | assertFalse(person1.equals(personNullDob));
70 | assertFalse(personNullDob.equals(person1));
71 | }
72 |
73 | @Test
74 | void testHashCode() {
75 | // Equal objects should have the same hash code
76 | assertEquals(person1.hashCode(), person1Copy.hashCode());
77 |
78 | // Different objects should have different hash codes
79 | assertNotEquals(person1.hashCode(), person2.hashCode());
80 | }
81 |
82 | @Test
83 | void testGetters() {
84 | assertEquals(1, person1.getId());
85 | assertEquals("Grace", person1.getFirst());
86 | assertEquals("Hopper", person1.getLast());
87 | assertEquals(LocalDate.of(1906, Month.DECEMBER, 9), person1.getDob());
88 | }
89 |
90 | @Test
91 | void testToString() {
92 | String expected = "Person[id=1, first=Grace, last=Hopper, dob=1906-12-09]";
93 | assertEquals(expected, person1.toString());
94 | }
95 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/inorder/OrderServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.inorder;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertTrue;
4 | import static org.mockito.Mockito.*;
5 |
6 | import org.junit.jupiter.api.Test;
7 | import org.junit.jupiter.api.extension.ExtendWith;
8 | import org.mockito.InOrder;
9 | import org.mockito.InjectMocks;
10 | import org.mockito.Mock;
11 | import org.mockito.junit.jupiter.MockitoExtension;
12 |
13 | @ExtendWith(MockitoExtension.class)
14 | public class OrderServiceTest {
15 |
16 | @Mock
17 | private PaymentService paymentServiceMock;
18 |
19 | @Mock
20 | private ShippingService shippingServiceMock;
21 |
22 | @InjectMocks
23 | private OrderService orderService;
24 |
25 | @Test
26 | public void processOrder() {
27 | // set the expectations on the mocks
28 | when(paymentServiceMock.processPayment(anyDouble())).thenReturn(true);
29 | when(shippingServiceMock.shipProduct(anyString())).thenReturn(true);
30 |
31 | // call the method to test
32 | double amount = 100.00;
33 | String address = "1313 Mockingbird Lane, New York, NY 10001";
34 | assertTrue(orderService.processOrder(amount, address));
35 |
36 | // verify that the mocked methods were called in the right order
37 | InOrder inOrder = inOrder(paymentServiceMock, shippingServiceMock);
38 | inOrder.verify(paymentServiceMock).processPayment(amount);
39 | inOrder.verify(shippingServiceMock).shipProduct(address);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/inorder/PaymentServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.inorder;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.mockito.InOrder;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertTrue;
7 | import static org.mockito.ArgumentMatchers.anyDouble;
8 | import static org.mockito.Mockito.*;
9 |
10 | class PaymentServiceTest {
11 |
12 | @Test
13 | void processPayment() {
14 | // create the mock
15 | PaymentProcessor processor = mock(PaymentProcessor.class);
16 |
17 | // set expectations on the mock
18 | when(processor.authorizePayment(anyDouble())).thenReturn(true);
19 | when(processor.capturePayment()).thenReturn(true);
20 |
21 | // inject the mock into the class under test
22 | PaymentService service = new PaymentService(processor);
23 |
24 | // call method under test
25 | assertTrue(service.processPayment(100.0));
26 |
27 | // verify the methods on the mock were called in the right order
28 | InOrder inOrder = inOrder(processor);
29 | inOrder.verify(processor).authorizePayment(anyDouble());
30 | inOrder.verify(processor).capturePayment();
31 | }
32 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/pubsub/PublisherTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.pubsub;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Disabled;
5 | import org.junit.jupiter.api.DisplayName;
6 | import org.junit.jupiter.api.Test;
7 | import org.mockito.InOrder;
8 |
9 | import static org.mockito.Mockito.*;
10 |
11 | class PublisherTest {
12 | private final Publisher pub = new Publisher();
13 | private final Subscriber sub1 = mock(Subscriber.class);
14 | private final Subscriber sub2 = mock(Subscriber.class);
15 |
16 | @BeforeEach
17 | void setUp() {
18 | pub.subscribe(sub1);
19 | pub.subscribe(sub2);
20 | }
21 |
22 | @Test
23 | void publisherSendsMessageToAllSubscribers() {
24 | pub.send("Hello");
25 |
26 | verify(sub1).onNext("Hello");
27 | verify(sub2).onNext("Hello");
28 | }
29 |
30 | @Test
31 | void handleMisbehavingSubscribers() {
32 | // Does not compile (because onNext returns void):
33 | // when(sub1.onNext(anyString())).thenThrow(new RuntimeException("Oops"));
34 |
35 | // sub1 throws an exception
36 | doThrow(RuntimeException.class).when(sub1).onNext(anyString());
37 | doNothing().when(sub2).onNext(anyString()); // legal, but redundant (it's the default)
38 |
39 | pub.send("message 1");
40 | pub.send("message 2");
41 |
42 | // both subscribers still received the messages
43 | verify(sub1, times(2)).onNext(matches("message \\d"));
44 | verify(sub2, times(2)).onNext(anyString());
45 | }
46 |
47 | @Test
48 | void testSendInOrder() { // Is this a good idea?? Overspecifying the implementation
49 | pub.send("Hello");
50 |
51 | InOrder inorder = inOrder(sub1, sub2);
52 | inorder.verify(sub1).onNext("Hello");
53 | inorder.verify(sub2).onNext("Hello");
54 | }
55 |
56 | @Test @DisplayName("Test send in parallel")
57 | @Disabled("This test fails because the order of the calls is not guaranteed")
58 | void testSendParallelCausesProblemsWithOrder() {
59 | pub.sendParallel("Hello");
60 |
61 | InOrder inorder = inOrder(sub1, sub2);
62 | inorder.verify(sub1).onNext("Hello");
63 | inorder.verify(sub2).onNext("Hello");
64 | }
65 |
66 | @Test
67 | void testSendParallel_withoutOrderVerification() {
68 | pub.sendParallel("Hello");
69 |
70 | // Verify both subscribers received the message (without order verification)
71 | verify(sub1).onNext("Hello");
72 | verify(sub2).onNext("Hello");
73 | }
74 |
75 | @Test
76 | void testSendParallel_withException() {
77 | // Configure sub1 to throw an exception
78 | doThrow(RuntimeException.class).when(sub1).onNext(anyString());
79 |
80 | // Call should not throw the exception outside the method
81 | pub.sendParallel("Message");
82 |
83 | // Verify both subscribers were called
84 | verify(sub1).onNext("Message");
85 | verify(sub2).onNext("Message");
86 | }
87 |
88 | @Test
89 | void publisherSendsMessageWithAPattern() {
90 | pub.send("Message 1");
91 | pub.send("Message 2");
92 |
93 | // Check for any string
94 | verify(sub1, times(2)).onNext(anyString());
95 | verify(sub2, times(2)).onNext(anyString());
96 |
97 | // Check for specific string pattern
98 | verify(sub1, times(2)).onNext(
99 | argThat(s -> s.matches("Message \\d")));
100 | verify(sub2, times(2)).onNext(
101 | argThat(s -> s.matches("Message [1-2]")));
102 |
103 | // Simpler, without custom matcher
104 | verify(sub1, times(2)).onNext(matches("Message \\d"));
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/AddingMachineAnnotationTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.mockito.InjectMocks;
6 | import org.mockito.Mock;
7 | import org.mockito.junit.MockitoJUnitRunner;
8 |
9 | import java.util.List;
10 | import java.util.stream.Stream;
11 |
12 | import static org.junit.Assert.assertEquals;
13 | import static org.mockito.Mockito.*;
14 |
15 | @RunWith(MockitoJUnitRunner.class)
16 | public class AddingMachineAnnotationTest {
17 | @Mock
18 | private List mockList;
19 |
20 | @InjectMocks
21 | private AddingMachine machine;
22 |
23 | // @Rule
24 | // public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
25 |
26 | // @Before
27 | // public void setUp() {
28 | // MockitoAnnotations.openMocks(this);
29 | // }
30 |
31 | @Test
32 | public void getTotalUsingLoop() {
33 | when(mockList.size()).thenReturn(3);
34 | when(mockList.get(0)).thenReturn(1);
35 | when(mockList.get(1)).thenReturn(2);
36 | when(mockList.get(2)).thenReturn(3);
37 |
38 | // Only requires the stub behavior,
39 | // i.e., that the get(i) methods return the expected values
40 | assertEquals(6, machine.getTotalUsingLoop());
41 |
42 | // Verify the protocol -- that the mock methods are called
43 | // the right number of times
44 | verify(mockList).size();
45 | verify(mockList, times(3)).get(anyInt());
46 | verify(mockList, never()).clear();
47 | }
48 |
49 | @Test
50 | public void getTotalUsingStream() {
51 | when(mockList.stream()).thenReturn(Stream.of(1, 2, 3));
52 |
53 | // Only requires the stub behavior,
54 | assertEquals(6, machine.getTotalUsingStream());
55 |
56 | // Verify the protocol -- that the mock methods are called
57 | // the right number of times
58 | verify(mockList).stream();
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/AddingMachineJUnit5Test.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.extension.ExtendWith;
5 | import org.mockito.InOrder;
6 | import org.mockito.InjectMocks;
7 | import org.mockito.Mock;
8 | import org.mockito.junit.jupiter.MockitoExtension;
9 |
10 | import java.util.List;
11 | import java.util.stream.Stream;
12 |
13 | import static org.junit.jupiter.api.Assertions.assertAll;
14 | import static org.junit.jupiter.api.Assertions.assertEquals;
15 | import static org.mockito.Mockito.*;
16 |
17 | @SuppressWarnings({"ResultOfMethodCallIgnored", "CommentedOutCode"})
18 | @ExtendWith(MockitoExtension.class)
19 | public class AddingMachineJUnit5Test {
20 | @Mock
21 | private List mockList;
22 |
23 | @InjectMocks
24 | private AddingMachine machine;
25 |
26 | // @Spy
27 | // private List spyList;
28 |
29 | @Test
30 | public void getTotalUsingLoop() {
31 | when(mockList.size()).thenReturn(3);
32 | when(mockList.get(0)).thenReturn(1);
33 | when(mockList.get(1)).thenReturn(2);
34 | when(mockList.get(2)).thenReturn(3);
35 |
36 | // Only requires the stub behavior,
37 | // i.e., that the get(i) methods return the expected values
38 | assertEquals(1 + 2 + 3, machine.getTotalUsingLoop());
39 |
40 | // Verify the protocol -- that the mock methods are called
41 | // the right number of times in the right order
42 | InOrder inOrder = inOrder(mockList);
43 |
44 | inOrder.verify(mockList).size();
45 | inOrder.verify(mockList, times(3)).get(anyInt());
46 | }
47 |
48 | @Test
49 | public void getTotalUsingAnyInt() {
50 | when(mockList.size()).thenReturn(3);
51 | // when(mockList.get(anyInt()))
52 | // .thenReturn(1)
53 | // .thenReturn(2)
54 | // .thenReturn(3);
55 |
56 | when(mockList.get(anyInt()))
57 | .thenReturn(1, 2, 3);
58 |
59 | // Only requires the stub behavior,
60 | // i.e., that the get(i) methods return the expected values
61 | // assertThat(nc.getTotalUsingLoop(), is(equalTo(6)));
62 | assertEquals(1 + 2 + 3, machine.getTotalUsingLoop());
63 |
64 | // Verify the protocol -- that the mock methods are called
65 | // the right number of times in the right order
66 | InOrder inOrder = inOrder(mockList);
67 |
68 | assertAll("verify stub methods called right num of times in proper order",
69 | () -> inOrder.verify(mockList).size(),
70 | () -> inOrder.verify(mockList, times(3)).get(anyInt()));
71 | }
72 |
73 | @Test
74 | public void getTotalUsingStream() {
75 | when(mockList.stream()).thenReturn(Stream.of(1, 2, 3));
76 |
77 | // Only requires the stub behavior,
78 | assertEquals(6, machine.getTotalUsingStream());
79 |
80 | // Verify the protocol -- that the mock methods are called
81 | // the right number of times
82 | verify(mockList).stream();
83 | }
84 |
85 | @Test
86 | void getTotalUsingLoopCustomMatcher() {
87 | when(mockList.size()).thenReturn(3);
88 | when(mockList.get(anyInt()))
89 | .thenReturn(1, 2, 3);
90 |
91 | assertEquals(1 + 2 + 3, machine.getTotalUsingLoop());
92 |
93 | // Custom matcher: intThat takes an ArgumentMatcher
94 | verify(mockList, times(3)).get(intThat(n -> n < 3));
95 |
96 | // This line throws an NPE. Don't use argThat for primitives.
97 | // verify(mockList, times(3)).get(argThat(n -> n < 3));
98 | }
99 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/AddingMachineTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.Arrays;
6 | import java.util.List;
7 | import java.util.stream.Stream;
8 |
9 | import static org.junit.Assert.*;
10 | import static org.mockito.BDDMockito.given;
11 | import static org.mockito.BDDMockito.then;
12 | import static org.mockito.Mockito.*;
13 |
14 | @SuppressWarnings("ResultOfMethodCallIgnored")
15 | public class AddingMachineTest {
16 |
17 | @Test
18 | public void getTotalUsingLoop() {
19 | // Create a stubbed list
20 | // Use no-arg version of mock() to avoid
21 | // compiler warning about unchecked cast
22 | List mockList = mock();
23 |
24 | // Set the expectations on the stub
25 | when(mockList.size()).thenReturn(3);
26 | when(mockList.get(0)).thenReturn(1);
27 | when(mockList.get(1)).thenReturn(2);
28 | when(mockList.get(2)).thenReturn(3);
29 |
30 | // Inject the stub into the class we want to test
31 | AddingMachine machine = new AddingMachine(mockList);
32 |
33 | // Test the method we care about
34 | assertEquals(1 + 2 + 3, machine.getTotalUsingLoop());
35 |
36 | // Verify the protocol between AddingMachine and the stubbed list
37 | verify(mockList).size();
38 | verify(mockList, times(3)).get(anyInt());
39 | }
40 |
41 | @Test
42 | public void getTotalUsingLoop_BDD() {
43 | // Create a stubbed list
44 | List mockList = mock();
45 |
46 | // Set the expectations on the stub
47 | given(mockList.size()).willReturn(3);
48 | given(mockList.get(anyInt())).willReturn(1, 2, 3);
49 |
50 | // Inject the stub into the class we want to test
51 | AddingMachine machine = new AddingMachine(mockList);
52 |
53 | // Test the method we care about
54 | assertEquals(1 + 2 + 3, machine.getTotalUsingLoop());
55 |
56 | // Verify the protocol between AddingMachine and the stubbed list
57 | then(mockList).should().size();
58 | then(mockList).should(times(3))
59 | .get(intThat(n -> n >= 0 && n < 3));
60 | // then(mockList).should(times(0)).remove(anyInt());
61 | then(mockList).shouldHaveNoMoreInteractions();
62 | }
63 |
64 | @Test // @SuppressWarnings("unchecked")
65 | public void getTotalUsingIterable() {
66 | List mockList = mock();
67 |
68 | when(mockList.iterator()).thenReturn(
69 | Arrays.asList(1, 2, 3).iterator());
70 |
71 | AddingMachine machine = new AddingMachine(mockList);
72 | assertEquals(1 + 2 + 3, machine.getTotalUsingIterable());
73 |
74 | verify(mockList).iterator();
75 | }
76 |
77 | @Test
78 | public void getTotalUsingStream() {
79 | List mockList = mock();
80 | when(mockList.stream()).thenReturn(Stream.of(1, 2, 3));
81 | // when(mockList.size()).thenReturn(3); // In JUnit 5, which is strict, this is not allowed
82 |
83 | AddingMachine machine = new AddingMachine(mockList);
84 |
85 | assertEquals(1 + 2 + 3, machine.getTotalUsingStream());
86 |
87 | verify(mockList).stream();
88 | }
89 |
90 | @Test
91 | public void getTotalUsingMockedIntegerList() {
92 | // Write our own mock implementation of List
93 | // Only the size() and get(0), get(1), and get(2) methods are stubbed
94 | List mockList = new MockListOfInteger();
95 |
96 | // Inject the stub into the class we want to test
97 | AddingMachine machine = new AddingMachine(mockList);
98 |
99 | // Test the method we care about
100 | assertEquals(1 + 2 + 3, machine.getTotalUsingLoop());
101 | }
102 |
103 | @Test // Not using Mockito at all
104 | public void getTotalWithRealList() {
105 | List realList = List.of(1, 2, 3);
106 |
107 | AddingMachine machine = new AddingMachine(realList);
108 |
109 | assertEquals(1 + 2 + 3, machine.getTotalUsingLoop());
110 | assertEquals(1 + 2 + 3, machine.getTotalUsingIterable());
111 | assertEquals(1 + 2 + 3, machine.getTotalUsingStream());
112 |
113 | // No built-in way to verify the method calls on real list
114 | }
115 |
116 | @Test
117 | public void spyOnList() {
118 | // Spy on a real list
119 | List spyList = spy(Arrays.asList(1, 2, 3));
120 |
121 | AddingMachine machine = new AddingMachine(spyList);
122 |
123 | assertEquals(1 + 2 + 3, machine.getTotalUsingLoop());
124 | assertEquals(1 + 2 + 3, machine.getTotalUsingIterable());
125 | assertEquals(1 + 2 + 3, machine.getTotalUsingStream());
126 |
127 | // Can verify a spy
128 | verify(spyList).size();
129 | verify(spyList, times(3)).get(anyInt());
130 | verify(spyList).iterator();
131 | verify(spyList).stream();
132 | }
133 |
134 | @Test
135 | public void partialMockOfList() {
136 | // Spy on a real list
137 | List spyList = spy(List.of());
138 |
139 | // Stub the size() method
140 | when(spyList.size()).thenReturn(3);
141 |
142 | // assertFalse(spyList.isEmpty()); // Uh oh. Is it empty or not?
143 | }
144 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/DocsTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.util.List;
6 |
7 | import static org.mockito.Mockito.mock;
8 | import static org.mockito.Mockito.verify;
9 |
10 | public class DocsTest {
11 | // "Let's verify some behaviour!"
12 | // https://javadoc.io/static/org.mockito/mockito-core/5.3.1/org/mockito/Mockito.html#verification
13 | @Test
14 | void testFromDocumentation() {
15 | //mock creation
16 | List mockedList = mock();
17 |
18 | //using mock object
19 | mockedList.add("one");
20 | mockedList.clear();
21 |
22 | //verification
23 | verify(mockedList).add("one");
24 | verify(mockedList).clear();
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/HelloServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.extension.ExtendWith;
5 | import org.mockito.InjectMocks;
6 | import org.mockito.Mock;
7 | import org.mockito.junit.jupiter.MockitoExtension;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertEquals;
10 | import static org.mockito.ArgumentMatchers.anyString;
11 | import static org.mockito.ArgumentMatchers.eq;
12 | import static org.mockito.Mockito.when;
13 |
14 | @ExtendWith(MockitoExtension.class)
15 | class HelloServiceTest {
16 |
17 | @Mock
18 | private TranslateService translateService;
19 |
20 | @InjectMocks
21 | private HelloService helloService;
22 |
23 | // Full end-to-end test
24 | @Test
25 | void testGreet() {
26 | HelloService hello = new HelloService(new TranslateService());
27 | String greeting = hello.greet("Dolly", "en");
28 | assertEquals("en translation: Hello, Dolly!", greeting);
29 | }
30 |
31 | @Test
32 | void testGreetWithFixedValues() {
33 | when(translateService.translate("Hello, Dolly!", "en"))
34 | .thenReturn("en translation: Hello, Dolly!");
35 |
36 | String greeting = helloService.greet("Dolly", "en");
37 | assertEquals("en translation: Hello, Dolly!", greeting);
38 | }
39 |
40 | // Mock the TranslateService for any string, but works only for "en"
41 | @Test
42 | void testGreetWithMock() {
43 | when(translateService.translate(anyString(), anyString()))
44 | .thenReturn("en translation: Hello, Dolly!");
45 |
46 | String greeting = helloService.greet("Dolly", "en");
47 | assertEquals("en translation: Hello, Dolly!", greeting);
48 | }
49 |
50 | // Mock the TranslateService for "en" only
51 | @Test
52 | void testGreetWithMockForEnglish() {
53 | when(translateService.translate(anyString(), eq("en")))
54 | .thenReturn("en translation: Hello, Dolly!");
55 |
56 | String greeting = helloService.greet("Dolly", "en");
57 | assertEquals("en translation: Hello, Dolly!", greeting);
58 | }
59 |
60 | // Mock the TranslateService for any language, using answer
61 | @Test
62 | void testGreetWithMockForEnglishWithAnswer() {
63 | when(translateService.translate(anyString(), anyString()))
64 | .thenAnswer(invocation -> invocation.getArgument(1) +
65 | " translation: Hello, Dolly!");
66 |
67 | String greeting = helloService.greet("Dolly", "en");
68 | assertEquals("en translation: Hello, Dolly!", greeting);
69 |
70 | greeting = helloService.greet("Dolly", "fr");
71 | assertEquals("fr translation: Hello, Dolly!", greeting);
72 | }
73 |
74 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/LoggingDemoTests.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.util.logging.Logger;
6 |
7 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
8 | import static org.mockito.Mockito.*;
9 |
10 | public class LoggingDemoTests {
11 | private final Logger logger =
12 | Logger.getLogger(LoggingDemoTests.class.getName());
13 |
14 | @Test
15 | public void testLogWithSpy() {
16 | // Spy on the logger
17 | Logger spy = spy(logger);
18 |
19 | // Inject the logger into the class under test
20 | LoggingDemo demo = new LoggingDemo(spy);
21 |
22 | // Invoke the method to test
23 | demo.doStuff("Hello, world!");
24 |
25 | // Verify that the info method of the logger was called
26 | verify(spy).info("Hello, world!");
27 | }
28 |
29 | @Test
30 | public void testLog() {
31 | LoggingDemo demo = new LoggingDemo(logger);
32 | assertDoesNotThrow(
33 | () -> demo.doStuff("Hello, world!"));
34 |
35 | // Nothing to test, because both
36 | // doStuff and info methods return void
37 | }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/LoggingStandardErrorTests.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.io.ByteArrayOutputStream;
6 | import java.io.PrintStream;
7 | import java.util.logging.Logger;
8 |
9 | import static org.assertj.core.api.Assertions.assertThat;
10 |
11 | public class LoggingStandardErrorTests {
12 | @Test
13 | void testLogWithStnErr() {
14 | Logger logger = Logger.getLogger(LoggingDemoTests.class.getName());
15 | LoggingDemo demo = new LoggingDemo(logger);
16 |
17 | ByteArrayOutputStream out = new ByteArrayOutputStream();
18 | ByteArrayOutputStream err = new ByteArrayOutputStream();
19 |
20 | System.setOut(new PrintStream(out));
21 | System.setErr(new PrintStream(err));
22 |
23 | demo.doStuff("Hello, world!");
24 |
25 | assertThat(out.toString()).contains("Doing useful stuff: Hello, world!");
26 | assertThat(err.toString()).contains("INFO: Hello, world!");
27 |
28 | System.setOut(System.out);
29 | System.setErr(System.err);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/LoggingWithOutputCaptureTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.jupiter.api.Disabled;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.extension.ExtendWith;
6 | import org.springframework.boot.test.system.CapturedOutput;
7 | import org.springframework.boot.test.system.OutputCaptureExtension;
8 |
9 | import java.util.logging.Logger;
10 |
11 | import static org.assertj.core.api.Assertions.assertThat;
12 |
13 | @Disabled("Working locally, but failing as a GitHub Action")
14 | @ExtendWith(OutputCaptureExtension.class)
15 | public class LoggingWithOutputCaptureTest {
16 | @Test
17 | void testLogWithOutputCapture(CapturedOutput outputCapture) {
18 | Logger logger = Logger.getLogger(LoggingDemoTests.class.getName());
19 | LoggingDemo demo = new LoggingDemo(logger);
20 | demo.doStuff("Hello, world!");
21 |
22 | assertThat(outputCapture.getOut())
23 | .contains("Doing useful stuff: Hello, world!");
24 | assertThat(outputCapture.getErr())
25 | .contains("INFO: Hello, world!");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/MockFinalTypesTests.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import org.junit.jupiter.api.Disabled;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.time.LocalDate;
7 | import java.time.Month;
8 |
9 | import static org.assertj.core.api.Assertions.assertThat;
10 | import static org.mockito.Mockito.*;
11 |
12 | @SuppressWarnings("CommentedOutCode")
13 | public class MockFinalTypesTests {
14 | @Test
15 | public void mockFinalClassLocalDate() {
16 | LocalDate mockDate = mock(LocalDate.class);
17 |
18 | when(mockDate.toString()).thenReturn("1969-07-20");
19 | when(mockDate.getYear()).thenReturn(1969);
20 |
21 | assertThat(mockDate).hasToString("1969-07-20");
22 | int year = mockDate.getYear();
23 | assertThat(year).isEqualTo(1969);
24 |
25 | verify(mockDate).getYear();
26 | }
27 |
28 | @Test
29 | public void mockAnEnum() {
30 | Month mockMonth = mock(Month.class);
31 |
32 | when(mockMonth.getValue()).thenReturn(7);
33 | when(mockMonth.name()).thenReturn("July");
34 |
35 | assertThat(mockMonth.name()).isEqualTo("July");
36 | int value = mockMonth.getValue();
37 | assertThat(value).isEqualTo(7);
38 |
39 | verify(mockMonth).getValue();
40 | verify(mockMonth).name();
41 | }
42 |
43 | @Test
44 | @Disabled("Mockito cannot mock wrapper types, String.class, or Class.class")
45 | public void mockFinalClassString() {
46 | /*
47 | String mockString = mock(String.class);
48 |
49 | when(mockString).thenReturn("hello");
50 | when(mockString.length()).thenReturn(5);
51 |
52 | assertThat(mockString).hasToString("hello");
53 | int length = mockString.length();
54 | assertThat(length).isEqualTo(5);
55 |
56 | verify(mockString).length();
57 | */
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/simple/MockListOfInteger.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.simple;
2 |
3 | import java.util.Collection;
4 | import java.util.Iterator;
5 | import java.util.List;
6 | import java.util.ListIterator;
7 |
8 | // Our own mocked list, to return a list containing the values 1, 2, 3
9 | // Only two methods are implemented: size, get(i)
10 | public class MockListOfInteger implements List {
11 | @Override
12 | public int size() {
13 | return 3;
14 | }
15 |
16 | @Override
17 | public Integer get(int index) {
18 | if (index == 0) return 1;
19 | if (index == 1) return 2;
20 | if (index == 2) return 3;
21 | return null;
22 | }
23 |
24 | @Override
25 | public boolean isEmpty() {
26 | return false;
27 | }
28 |
29 | @Override
30 | public boolean contains(Object o) {
31 | return false;
32 | }
33 |
34 | @Override
35 | public Iterator iterator() {
36 | return new Iterator<>() {
37 | @Override
38 | public boolean hasNext() {
39 | return false;
40 | }
41 |
42 | @Override
43 | public Integer next() {
44 | return null;
45 | }
46 | };
47 | }
48 |
49 | @Override
50 | public Object[] toArray() {
51 | return new Object[0];
52 | }
53 |
54 | @Override
55 | public T[] toArray(T[] a) {
56 | return a;
57 | }
58 |
59 | @Override
60 | public boolean add(Integer integer) {
61 | return true;
62 | }
63 |
64 | @Override
65 | public boolean remove(Object o) {
66 | return false;
67 | }
68 |
69 | @Override
70 | public boolean containsAll(Collection> c) {
71 | return false;
72 | }
73 |
74 | @Override
75 | public boolean addAll(Collection extends Integer> c) {
76 | return false;
77 | }
78 |
79 | @Override
80 | public boolean addAll(int index, Collection extends Integer> c) {
81 | return false;
82 | }
83 |
84 | @Override
85 | public boolean removeAll(Collection> c) {
86 | return false;
87 | }
88 |
89 | @Override
90 | public boolean retainAll(Collection> c) {
91 | return false;
92 | }
93 |
94 | @Override
95 | public void clear() {
96 |
97 | }
98 |
99 | @Override
100 | public Integer set(int index, Integer element) {
101 | return null;
102 | }
103 |
104 | @Override
105 | public void add(int index, Integer element) {
106 |
107 | }
108 |
109 | @Override
110 | public Integer remove(int index) {
111 | return null;
112 | }
113 |
114 | @Override
115 | public int indexOf(Object o) {
116 | return 0;
117 | }
118 |
119 | @Override
120 | public int lastIndexOf(Object o) {
121 | return 0;
122 | }
123 |
124 | @Override
125 | public ListIterator listIterator() {
126 | return new ListIterator<>() {
127 | @Override
128 | public boolean hasNext() {
129 | return false;
130 | }
131 |
132 | @Override
133 | public Integer next() {
134 | return null;
135 | }
136 |
137 | @Override
138 | public boolean hasPrevious() {
139 | return false;
140 | }
141 |
142 | @Override
143 | public Integer previous() {
144 | return null;
145 | }
146 |
147 | @Override
148 | public int nextIndex() {
149 | return 0;
150 | }
151 |
152 | @Override
153 | public int previousIndex() {
154 | return 0;
155 | }
156 |
157 | @Override
158 | public void remove() {
159 |
160 | }
161 |
162 | @Override
163 | public void set(Integer integer) {
164 |
165 | }
166 |
167 | @Override
168 | public void add(Integer integer) {
169 |
170 | }
171 | };
172 | }
173 |
174 | @Override
175 | public ListIterator listIterator(int index) {
176 | return new ListIterator<>() {
177 | @Override
178 | public boolean hasNext() {
179 | return false;
180 | }
181 |
182 | @Override
183 | public Integer next() {
184 | return null;
185 | }
186 |
187 | @Override
188 | public boolean hasPrevious() {
189 | return false;
190 | }
191 |
192 | @Override
193 | public Integer previous() {
194 | return null;
195 | }
196 |
197 | @Override
198 | public int nextIndex() {
199 | return 0;
200 | }
201 |
202 | @Override
203 | public int previousIndex() {
204 | return 0;
205 | }
206 |
207 | @Override
208 | public void remove() {
209 |
210 | }
211 |
212 | @Override
213 | public void set(Integer integer) {
214 |
215 | }
216 |
217 | @Override
218 | public void add(Integer integer) {
219 |
220 | }
221 | };
222 | }
223 |
224 | @Override
225 | public List subList(int fromIndex, int toIndex) {
226 | return this;
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/wikipedia/BioServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.mockito.AdditionalAnswers;
5 | import org.mockito.MockedStatic;
6 |
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 | import static org.assertj.core.api.Assertions.assertThat;
11 | import static org.junit.jupiter.api.Assertions.assertEquals;
12 | import static org.mockito.ArgumentMatchers.anyString;
13 | import static org.mockito.Mockito.mockStatic;
14 | import static org.mockito.Mockito.times;
15 |
16 | class BioServiceTest {
17 | @Test // Integration test
18 | void checkBios() {
19 | BioService service = new BioService("Anita Borg", "Ada Lovelace",
20 | "Grace Hopper", "Barbara Liskov");
21 | List bios = service.getBios();
22 | assertEquals(4, bios.size());
23 | bios.forEach(bio -> {
24 | // System.out.println(bio);
25 | String[] strings = bio.split("=");
26 | String[] bioStrings = strings[1].split("\\n");
27 | System.out.println("Title: " + strings[0].substring(1));
28 | Arrays.stream(bioStrings)
29 | .forEach(System.out::println);
30 | System.out.println("-------------------");
31 | });
32 | }
33 |
34 | @Test
35 | void testBioServiceWithMocks() {
36 | BioService service = new BioService(
37 | "Anita Borg", "Ada Lovelace", "Grace Hopper", "Barbara Liskov");
38 | try (MockedStatic mocked = mockStatic(WikiUtil.class)) {
39 | mocked.when(() -> WikiUtil.getWikipediaExtract(anyString()))
40 | .thenAnswer(AdditionalAnswers.returnsFirstArg());
41 | assertThat(service.getBios()).hasSize(4);
42 | mocked.verify(() -> WikiUtil.getWikipediaExtract(anyString()), times(4));
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/wikipedia/WikiPageTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.*;
6 |
7 | class WikiPageTest {
8 |
9 | @Test
10 | void testGettersAndSetters() {
11 | WikiPage page = new WikiPage();
12 |
13 | // Test pageId
14 | page.setPageid(123);
15 | assertEquals(123, page.getPageid());
16 |
17 | // Test namespace
18 | page.setNs(0);
19 | assertEquals(0, page.getNs());
20 |
21 | // Test title
22 | page.setTitle("Grace Hopper");
23 | assertEquals("Grace Hopper", page.getTitle());
24 |
25 | // Test extract
26 | String extract = "Grace Brewster Hopper was an American computer scientist, " +
27 | "mathematician, and United States Navy rear admiral.";
28 | page.setExtract(extract);
29 | assertEquals(extract, page.getExtract());
30 |
31 | // Test missing flag
32 | page.setMissing(true);
33 | assertTrue(page.getMissing());
34 |
35 | page.setMissing(false);
36 | assertFalse(page.getMissing());
37 | }
38 |
39 | @Test
40 | void testToString() {
41 | WikiPage page = new WikiPage();
42 | page.setPageid(123);
43 | page.setNs(0);
44 | page.setTitle("Ada Lovelace");
45 | page.setExtract("Ada Lovelace was an English mathematician and writer.");
46 | page.setMissing(false);
47 |
48 | String expected = "WikiPage{" +
49 | "pageid=123" +
50 | ", ns=0" +
51 | ", title='Ada Lovelace'" +
52 | ", extract='Ada Lovelace was an English mathematician and writer.'" +
53 | ", missing=false" +
54 | '}';
55 |
56 | assertEquals(expected, page.toString());
57 | }
58 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/wikipedia/WikiResponseTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import static org.junit.jupiter.api.Assertions.*;
9 |
10 | class WikiResponseTest {
11 |
12 | @Test
13 | void testGettersAndSetters() {
14 | WikiResponse response = new WikiResponse();
15 |
16 | // Test batchcomplete
17 | response.setBatchcomplete("true");
18 | assertEquals("true", response.getBatchcomplete());
19 |
20 | // Test query and pages
21 | List pages = new ArrayList<>();
22 | WikiPage page = new WikiPage();
23 | page.setTitle("Ada Lovelace");
24 | page.setExtract("Ada Lovelace was an English mathematician and writer.");
25 | pages.add(page);
26 |
27 | WikiQuery query = new WikiQuery();
28 | query.setPages(pages);
29 |
30 | response.setQuery(query);
31 | assertEquals(query, response.getQuery());
32 | assertEquals(pages, response.getQuery().getPages());
33 | }
34 |
35 | @Test
36 | void testToString() {
37 | WikiResponse response = new WikiResponse();
38 | response.setBatchcomplete("true");
39 |
40 | List pages = new ArrayList<>();
41 | WikiPage page = new WikiPage();
42 | page.setTitle("Ada Lovelace");
43 | page.setExtract("Ada Lovelace was an English mathematician and writer.");
44 | pages.add(page);
45 |
46 | WikiQuery query = new WikiQuery();
47 | query.setPages(pages);
48 |
49 | response.setQuery(query);
50 |
51 | String result = response.toString();
52 | assertNotNull(result);
53 | assertTrue(result.contains("batchcomplete=true"));
54 | }
55 | }
--------------------------------------------------------------------------------
/src/test/java/com/kousenit/wikipedia/WikiUtilTest.java:
--------------------------------------------------------------------------------
1 | package com.kousenit.wikipedia;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.assertj.core.api.Assertions.assertThat;
6 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
7 |
8 | class WikiUtilTest {
9 |
10 | @Test
11 | void getStringResponse() {
12 | String graceHopper = WikiUtil.getWikipediaExtract("Grace Hopper");
13 | System.out.println(graceHopper);
14 | assertThat(graceHopper).contains("Grace", "Hopper");
15 | }
16 |
17 | @Test
18 | void getResponseNotFound() {
19 | assertThatExceptionOfType(RuntimeException.class)
20 | .isThrownBy(() -> WikiUtil.getWikipediaExtract("Not a real page"))
21 | .withMessageContaining("Page not found");
22 | }
23 | }
--------------------------------------------------------------------------------
/src/test/resources/junit-platform.properties:
--------------------------------------------------------------------------------
1 | junit.platform.output.capture.stdout=true
2 | junit.platform.output.capture.stderr=true
3 |
--------------------------------------------------------------------------------
/src/test/resources/mappings/response.json:
--------------------------------------------------------------------------------
1 | {
2 | "people": [
3 | {
4 | "craft": "Discovery One",
5 | "name": "David Bowman"
6 | },
7 | {
8 | "craft": "Discovery One",
9 | "name": "Frank Poole"
10 | },
11 | {
12 | "craft": "Discovery One",
13 | "name": "HAL 9000"
14 | }
15 | ],
16 | "message": "success",
17 | "number": 3
18 | }
--------------------------------------------------------------------------------