diff --git a/.dependabot/config.yml b/.dependabot/config.yml deleted file mode 100644 index 16be16a270..0000000000 --- a/.dependabot/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -version: 1 - -update_configs: - - package_manager: "java:gradle" - directory: "/" - update_schedule: "daily" - # Redundant - default repository branch by default - target_branch: "release/3.x" diff --git a/.editorconfig b/.editorconfig index 925d8821f4..5f7264121b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,9 +6,41 @@ insert_final_newline = true trim_trailing_whitespace = true indent_style = space indent_size = 4 +charset = utf-8 [{*.yml,*.yaml}] indent_size = 2 ij_continuation_indent_size = 2 ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_line_breaks = true +ij_any_block_comment_at_first_column = false +ij_java_line_comment_at_first_column = false +ij_java_line_comment_add_space = true + +[*.java] +ij_java_align_multiline_throws_list = true +ij_java_align_multiline_annotation_parameters = true +ij_java_annotation_parameter_wrap = off +ij_java_blank_lines_after_imports = 1 +ij_java_blank_lines_before_imports = 1 +ij_java_class_count_to_use_import_on_demand = 100 +ij_java_names_count_to_use_import_on_demand = 100 +ij_java_imports_layout = static java.**,static javax.**,$*,|,java.**,javax.**,* +ij_java_insert_inner_class_imports = true +ij_java_layout_static_imports_separately = true +ij_java_method_call_chain_wrap = off +ij_java_throws_list_wrap = off +ij_java_block_comment_at_first_column = false +ij_java_line_comment_at_first_column = false +ij_java_line_comment_add_space = true + +[{*.kt,*.kts}] +ij_kotlin_block_comment_at_first_column = false +ij_kotlin_line_comment_at_first_column = false +ij_kotlin_line_comment_add_space = true + +[*.gradle] +ij_groovy_block_comment_at_first_column = false +ij_groovy_line_comment_at_first_column = false +ij_groovy_line_comment_add_space = true + diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1cdaaa1fac..967177cc4d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,19 +6,15 @@ **If looking for support** -* Search / Ask question on [stackoverflow](http://stackoverflow.com/questions/tagged/mockito) -* Go to the [mockito mailing-list](http://groups.google.com/group/mockito) (moderated) -* Issues should always have a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org) (same as any question on stackoverflow.com) +* Search / Ask a question on [Stack Overflow / Questions tagged [mockito]](https://stackoverflow.com/questions/tagged/mockito) +* Go to the [mockito mailing-list](https://groups.google.com/group/mockito) (moderated) +* Issues should always have a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org) (same as any question on [Stack Overflow](https://stackoverflow.com)) # Contributing to Mockito -Which branch : -* On mockito 3.x (or 2.x), make your pull request target `release/3.x` (or `release/2.x`) -* On next mockito version make your pull request target `release/3.x` - ## Pull request criteria -* **At least one commit message** in the PR starts with `Fixes #id : ` where `id` is an [issue tracker](https://github.com/mockito/mockito/issues) id. This allows automated release notes generation. Also GitHub will track the issue and [close it](https://github.com/blog/1386-closing-issues-via-commit-messages) when the PR is merged. +* **At least one commit message** in the PR ends with `Fixes #id` where `id` is an [issue tracker](https://github.com/mockito/mockito/issues) id. This allows automated release notes generation. Also GitHub will track the issue and [close it](https://github.com/blog/1386-closing-issues-via-commit-messages) when the PR is merged. * Use `@since` tags for new public APIs * Include tests * Document public APIs with examples @@ -46,19 +42,31 @@ Things we pay attention in a PR : * On pull requests, please document the change, what it brings, what is the benefit. * **Clean commit history** in the topic branch in your fork of the repository, even during review. That means that commits are _rebased_ and _squashed_ if necessary, so that each commit clearly changes one things and there are no extraneous fix-ups. - For that matter it's possible to commit [_semantic_ changes](http://lemike-de.tumblr.com/post/79041908218/semantic-commits). _Tests are an asset, so is history_. + _Tests are an asset, so is history_. + + _Example gratia_ (based on https://cbea.ms/git-commit/): + + ``` + Enable feature X to do Y + + Include some background information here. - _Exemple gratia_: + Fixes #73 + ``` ``` - Fixes #73 : The new feature - Fixes #73 : Refactors this part of Mockito to make feature possible + Fix bug B with feature A + + Include some background information here. + Add example scenario/context. + + Fixes #73 ``` * In the code, always test your feature / change, in unit tests and in our `acceptance test suite` located in `org.mockitousage`. Older tests will be migrated when a test is modified. * New test methods should follow a snake case convention (`ensure_that_stuff_is_doing_that`), this allows the test name to be fully expressive on intent while still readable. * When reporting errors to the users, if it's a user report report it gently and explain how a user should deal with it, see the `Reporter` class. However not all errors should go there, some unlikely technical errors don't need to be in the `Reporter` class. -* Documentation !!! Always document with love the public API. Internals could use some love too. In all cases the code should _auto-document_ itself like any [well designed API](rebased and squashed if necessary, so that each commit clearly changes one things and there are no extraneous fix-ups). +* Documentation !!! Always document with love the public API. Internals could use some love too. In all cases the code should _auto-document_ itself like any well-designed API. * We use (4) spaces instead of tabs. Make sure line ending is Unix style (LF). More on line ending on the [Github help](https://help.github.com/articles/dealing-with-line-endings/). @@ -73,14 +81,14 @@ This section is not about some kind of fruitless tabs vs spaces debate. It's abo _This includes IntelliJ IDEA instructions, however we are sure there's similar settings in all major IDEs._ -But first of all, make sure that : +But first of all, make sure that : * Don't use tabs, only spaces * Character encoding is **UTF-8** * Line ending character is unix-style **`LF`** * New line is added at end of file: `IntelliJ setting > Editor > General > Ensure line feed at file end on save` -For most editors, this should be automatically enforced by [EditorConfig](http://editorconfig.org/). +For most editors, this should be automatically enforced by [EditorConfig](https://editorconfig.org/). Check if your editor has a built-in plugin or if you need to download one. IntelliJ has a built-in plugin, for Eclipse you need to download [this plugin](https://github.com/ncjones/editorconfig-eclipse#readme). @@ -100,6 +108,7 @@ Imports must be sorted in the following order 1. blank line 1. `import java.*` 1. `import javax.*` +1. blank line 1. `import all other imports` This order can be set in `IntelliJ setting > Editor > Code Style > Java > Imports > Import Layout` @@ -108,8 +117,8 @@ Also make sure that * One blank lines before imports. * One blank lines after imports. * Never import with wildcard `*` - * Set `IntelliJ setting > Editor > Code Style > Java > Imports > Class count to use import with '*'` to `100` - * Set `IntelliJ setting > Editor > Code Style > Java > Imports > Names count to use import static with '*'` to `100` + * Set `IntelliJ setting > Editor > Code Style > Java > Imports > Class count to use import with '*'` to `100` + * Set `IntelliJ setting > Editor > Code Style > Java > Imports > Names count to use import static with '*'` to `100` ### Alignment @@ -164,7 +173,7 @@ We found vertical alignment helping when reading the code, for that reason we wa ```java @Mock(answer = Answers.RETURNS_DEFAULTS, - serializable = true, + serializable = true, extraInterfaces = { List.class, YetAnotherInterface.class }) ``` @@ -188,3 +197,7 @@ We found vertical alignment helping when reading the code, for that reason we wa 1. For parameter `Throws list` choose : `Do not wrap` 2. For sub-parameter `Align when multiline` tick the checkbox +## Gradle Tips + +1. It is possible to run `./gradlew dependencyUpdates` to find out of date dependencies, including tools. Note that this + may show beta or alpha dependencies. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 467f81e489..a8286ee4cb 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,10 +1,10 @@ > Hey, -> +> > First thanks for reporting, in order to help us to classify issue can you make sure the following check boxes are checked ? -> +> > If this is about mockito usage, the better way is to reach out to -> -> - stackoverflow : http://stackoverflow.com/questions/tagged/mockito +> +> - stackoverflow : https://stackoverflow.com/questions/tagged/mockito > - the mailing-list : https://groups.google.com/forum/#!forum/mockito / mockito@googlegroups.com > (Note mailing-list is moderated to avoid spam) > @@ -20,6 +20,6 @@ check that - [ ] Provide versions (mockito / jdk / os / any other relevant information) - [ ] Provide a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org) of the issue (same as any question on stackoverflow.com) - - [ ] Read the [contributing guide](https://github.com/mockito/mockito/blob/release/3.x/.github/CONTRIBUTING.md) + - [ ] Read the [contributing guide](https://github.com/mockito/mockito/blob/main/.github/CONTRIBUTING.md) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5309c02649..6fbe6948a6 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,28 +1,13 @@ -> Hey, -> -> Thanks for the contribution, this is awesome. -> As you may have read, project members have somehow an opinionated view on what and how should be -> Mockito, e.g. we don't want mockito to be a feature bloat. -> There may be a thorough review, with feedback -> code change loop. -> -> Which branch : -> - On mockito 3.x, make your pull request target `release/3.x` -> - On mockito 2.x, make your pull request target `release/2.x` (2.x is in maintenance mode) -> -> _This block can be removed_ -> _Something wrong in the template fix it here `.github/PULL_REQUEST_TEMPLATE.md` +## Checklist -check list - - - [ ] Read the [contributing guide](https://github.com/mockito/mockito/blob/release/3.x/.github/CONTRIBUTING.md) + - [ ] Read the [contributing guide](https://github.com/mockito/mockito/blob/main/.github/CONTRIBUTING.md) - [ ] PR should be motivated, i.e. what does it fix, why, and if relevant how - [ ] If possible / relevant include an example in the description, that could help all readers including project members to get a better picture of the change - [ ] Avoid other runtime dependencies - [ ] Meaningful commit history ; intention is important please rebase your commit history so that each commit is meaningful and help the people that will explore a change in 2 years - - [ ] The pull request follows coding style + - [ ] The pull request follows coding style (run `./gradlew spotlessApply` for auto-formatting) - [ ] Mention `Fixes #` in the description _if relevant_ - - [ ] At least one commit should mention `Fixes #` _if relevant_ - + - [ ] At least one commit should end with `Fixes #` _if relevant_ diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..1ef0730a67 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..1a6cf82fdc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,234 @@ +# +# CI build that assembles artifacts and runs tests. +# If validation is successful this workflow releases from the main dev branch. +# +# - skipping CI: add [skip ci] to the commit message +# - skipping release: add [skip release] to the commit message +# +name: CI + +on: + push: + branches: ['main'] + tags: [v*] + pull_request: + branches: ['**'] + +permissions: + contents: read + +jobs: + + # + # Main build job + # + build: + runs-on: ubuntu-latest + if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')" + + # Definition of the build matrix + strategy: + matrix: + java: [11, 17, 21] + entry: + - { mock-maker: 'mock-maker-default', member-accessor: 'member-accessor-default' } + - { mock-maker: 'mock-maker-inline', member-accessor: 'member-accessor-module' } + - { mock-maker: 'mock-maker-subclass', member-accessor: 'member-accessor-module' } + - { mock-maker: 'mock-maker-subclass', member-accessor: 'member-accessor-reflection' } + - { mock-maker: 'mock-maker-inline', member-accessor: 'member-accessor-reflection' } + + # All build steps + # SINGLE-MATRIX-JOB means that the step does not need to be executed on every job in the matrix + steps: + + - name: 1. Check out code + uses: actions/checkout@v4 # https://github.com/actions/checkout + with: + fetch-depth: '0' # https://github.com/shipkit/shipkit-changelog#fetch-depth-on-ci + + - name: 2. Set up Java for running Gradle build + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 17 + cache: 'gradle' + + - name: 3. Validate Gradle wrapper + if: matrix.java == 11 && matrix.entry.mock-maker == 'mock-maker-default' # SINGLE-MATRIX-JOB + uses: gradle/actions/wrapper-validation@v4 # https://github.com/gradle/wrapper-validation-action + + - name: 4. Build and check reproducibility of artifacts (single job only) + if: matrix.java == 11 && matrix.entry.mock-maker == 'mock-maker-default' # SINGLE-MATRIX-JOB + run: ./check_reproducibility.sh + + - name: 5. Spotless check (single job only). Run './gradlew spotlessApply' locally if this job fails. + if: matrix.java == 11 && matrix.entry.mock-maker == 'mock-maker-default' # SINGLE-MATRIX-JOB + run: > + ./gradlew + spotlessCheck + --stacktrace + --scan + + - name: 6. Build on Java ${{ matrix.java }} with ${{ matrix.entry.mock-maker }} and ${{ matrix.entry.member-accessor }} + run: > + ./gradlew + -Pmockito.test.java=${{ matrix.java }} + build + --stacktrace + --scan + env: + MOCK_MAKER: ${{ matrix.entry.mock-maker }} + MEMBER_ACCESSOR: ${{ matrix.entry.member-accessor }} + + - name: 7. Generate coverage report + run: > + ./gradlew + -Pmockito.test.java=${{ matrix.java }} + coverageReport + --stacktrace + --scan + + - name: 8. Upload coverage report + uses: codecov/codecov-action@v5 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + files: mockito-core/build/reports/jacoco/mockitoCoverage/mockitoCoverage.xml + fail_ci_if_error: true + + # + # Android build job + # + android: + runs-on: ubuntu-latest + if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')" + timeout-minutes: 30 + + # Definition of the build matrix + strategy: + matrix: + # Minimum supported and maximum available. + android-api: [ 26, 33 ] + + # All build steps + steps: + - name: 1. Check out code + uses: actions/checkout@v4 + with: + fetch-depth: '0' # https://github.com/shipkit/shipkit-changelog#fetch-depth-on-ci + + - name: 2. Set up Java for running Gradle build + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 17 + cache: 'gradle' + + - name: 3. Enable KVM. + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: 4. Run Android tests on Android API level ${{ matrix.android-api }} + uses: reactivecircus/android-emulator-runner@v2 + with: + arch: x86_64 + api-level: ${{ matrix.android-api }} + # Override default "-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim" + # See emulator manual for reference: https://developer.android.com/studio/run/emulator-commandline + emulator-options: > + -no-window + -gpu swiftshader_indirect + -no-snapshot + -noaudio + -no-boot-anim + -camera-back none + -camera-front none + # See logcat manual for reference: https://developer.android.com/studio/command-line/logcat + script: | + # Capture logcat output from "Launch Emulator" to a file. + adb logcat -d > emulator-startup.log + # Shorten the logcat output, by truncating at this point, the relevant part is yet to come. + # Best effort, could fail with "failed to clear the 'main' log", + # because something is locking logcat, so try a few times, and ignore errors each time. + adb logcat --clear || true + adb logcat --clear || true + adb logcat --clear || true + # Capture full logcat output to a file. + adb logcat > emulator.log & echo $! > logcat_file.pid + # Output instrumentation test logs to the GitHub Actions output. + adb logcat "*:S MonitoringInstr:V AndroidJUnitRunner:V TestRequestBuilder:V TestExecutor:V TestRunner:V" --format=color & echo $! > logcat_console.pid + + echo 0 > gradle.exit # Set a default exit code. + # Run the actual tests (suppress build failures by saving the exit code). + ./gradlew :mockito-integration-tests:android-tests:connectedCheck --no-daemon --no-build-cache || echo $? > gradle.exit + + # Stop capturing logcat output. + kill $(cat logcat_file.pid) || echo "::warning file=.github/workflows/ci.yml::Logcat process $(cat logcat_file.pid) didn't exist." + kill $(cat logcat_console.pid) || echo "::warning file=.github/workflows/ci.yml::Logcat process $(cat logcat_console.pid) didn't exist." + # Make sure the step fails if the tests failed. + exit $(cat gradle.exit) + + - name: 5. Upload artifact "android-tests-results-${{ matrix.android-api }}" + if: success() || failure() + uses: actions/upload-artifact@v4 + with: + name: androidTest-results-${{ matrix.android-api }} + path: | + ${{ github.workspace }}/mockito-integration-tests/android-tests/build/reports/android-tests/connected/** + ${{ github.workspace }}/emulator.log + ${{ github.workspace }}/emulator-startup.log + + # :mockito-integration-tests:android-tests:connectedCheck (which depends on :mockito-integration-tests:android-tests:createDebugAndroidTestCoverageReport) already generated coverage report. + - name: 6. Upload coverage report + uses: codecov/codecov-action@v5 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + files: mockito-integration-tests/android-tests/build/reports/coverage/android-tests/debug/connected/report.xml + fail_ci_if_error: true + + # + # Release job, only for pushes to the main development branch + # + release: + permissions: + contents: write + runs-on: ubuntu-latest + needs: [build] # build job must pass before we can release + + if: github.event_name == 'push' + && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) + && github.repository == 'mockito/mockito' + && !contains(toJSON(github.event.commits.*.message), '[skip release]') + + steps: + + - name: 1. Check out code + uses: actions/checkout@v4 # https://github.com/actions/checkout + with: + fetch-depth: '0' # https://github.com/shipkit/shipkit-changelog#fetch-depth-on-ci + + - name: 2. Set up Java for running Gradle build + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 21 + cache: 'gradle' + + - name: 3. Build and release + run: > + ./gradlew + githubRelease + publishToSonatype + closeAndReleaseStagingRepositories + releaseSummary + --info + --stacktrace + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + NEXUS_TOKEN_USER: ${{secrets.NEXUS_TOKEN_USER}} + NEXUS_TOKEN_PWD: ${{secrets.NEXUS_TOKEN_PWD}} + PGP_KEY: ${{secrets.PGP_KEY}} + PGP_PWD: ${{secrets.PGP_PWD}} diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml deleted file mode 100644 index 405a2b3065..0000000000 --- a/.github/workflows/gradle-wrapper-validation.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: "Validate Gradle Wrapper" -on: [push, pull_request] - -jobs: - validation: - name: "Validation" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: gradle/wrapper-validation-action@v1 diff --git a/.gitignore b/.gitignore index 9d0c115582..2638ca5724 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Mac +.DS_Store + # Intellij *.iml *.ipr @@ -12,6 +15,9 @@ .settings/ bin/ +# VSCode +.vscode/ + # Gradle & builds build build-cache @@ -21,3 +27,7 @@ out classes .gradletasknamecache *.log + +# Used to check reproducibility of Mockito jars +checksums/ +/.tool-versions diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 26c444f3ef..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,58 +0,0 @@ -# More details on how to configure the Travis build -# https://docs.travis-ci.com/user/customizing-the-build/ - -# Speed up build by leveraging travis caches -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - -# Enabling container based infrastructure hoping it will help the build speed <= this didn't work well, so it's reverted -# see https://docs.travis-ci.com/user/migrating-from-legacy/ and https://docs.travis-ci.com/user/ci-environment -sudo: true - -language: java - -dist: trusty - -matrix: - include: - - jdk: openjdk8 - - jdk: openjdk8 - env: SKIP_RELEASE=true MOCK_MAKER=mock-maker-inline - - jdk: openjdk9 - env: SKIP_RELEASE=true - - jdk: openjdk9 - env: SKIP_RELEASE=true MOCK_MAKER=mock-maker-inline - - jdk: openjdk9 - env: SKIP_RELEASE=true SIMULATE_JAVA11=true - - jdk: openjdk10 - env: SKIP_RELEASE=true - - jdk: openjdk10 - env: SKIP_RELEASE=true MOCK_MAKER=mock-maker-inline - - jdk: openjdk11 - env: SKIP_RELEASE=true - - jdk: openjdk11 - env: SKIP_RELEASE=true MOCK_MAKER=mock-maker-inline - -branches: - #Don't build tags - except: - - /^v\d/ - -#Below skips the installation step completely (https://docs.travis-ci.com/user/customizing-the-build/#Skipping-the-Installation-Step) -#We need it because otherwise Travis CI injects an awkward './gradlew assemble' step into the CI workflow -#We want to control and decide what Gradle tasks are executed -install: - - true - -script: - # We are using && below on purpose - # ciPerformRelease must run only when the entire build has completed - # This guarantees that no release steps are executed when the build or tests fail - - ./gradlew spotlessCheck && ./gradlew build idea -s && ./gradlew ciPerformRelease - -after_success: - #Generates coverage report: - - ./gradlew coverageReport -Pjacoco -s --scan && cp build/reports/jacoco/mockitoCoverage/mockitoCoverage.xml jacoco.xml || echo "Code coverage failed" - - bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports" diff --git a/README.md b/README.md index a69f94874a..40a805c948 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,85 @@ - - +Mockito Most popular mocking framework for Java -[![Build Status](https://travis-ci.org/mockito/mockito.svg?branch=release/3.x)](https://travis-ci.org/mockito/mockito) +[![CI](https://github.com/mockito/mockito/workflows/CI/badge.svg)](https://github.com/mockito/mockito/actions?query=workflow%3ACI) [![Coverage Status](https://img.shields.io/codecov/c/github/mockito/mockito.svg)](https://codecov.io/github/mockito/mockito) -[![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/mockito/mockito/blob/release/3.x/LICENSE) +[![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/mockito/mockito/blob/main/LICENSE) -[![Release Notes](https://img.shields.io/badge/release%20notes-3.x-yellow.svg)](https://github.com/mockito/mockito/blob/release/3.x/doc/release-notes/official.md) +[![Release Notes](https://img.shields.io/badge/release%20notes-5.x-yellow.svg)](https://github.com/mockito/mockito/releases/) [![Maven Central](https://img.shields.io/maven-central/v/org.mockito/mockito-core.svg)](https://search.maven.org/artifact/org.mockito/mockito-core/) -[![Bintray](https://img.shields.io/bintray/v/mockito/maven/mockito-development)](https://bintray.com/mockito/maven/mockito/_latestVersion) [![Javadoc](https://www.javadoc.io/badge/org.mockito/mockito-core.svg)](https://www.javadoc.io/doc/org.mockito/mockito-core) -## Current version is 3.x -Still on Mockito 1.x? See [what's new](https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2) in Mockito 2! [Mockito 3](https://github.com/mockito/mockito/releases/tag/v3.0.0) does not introduce any breaking API changes, but now requires Java 8 over Java 6 for Mockito 2. +## Current version is 5.x +Still on Mockito 1.x? See [what's new](https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2) in Mockito 2! +[Mockito 3](https://github.com/mockito/mockito/releases/tag/v3.0.0) does not introduce any breaking API changes, but now requires Java 8 over Java 6 for Mockito 2. +[Mockito 4](https://github.com/mockito/mockito/releases/tag/v4.0.0) removes deprecated API. +[Mockito 5](https://github.com/mockito/mockito/releases/tag/v5.0.0) switches the default mockmaker to mockito-inline, and now requires Java 11. +Only one major version is supported at a time, and changes are not backported to older versions. ## Mockito for enterprise -Available as part of the Tidelift Subscription +Available as part of the [Tidelift](https://tidelift.com/subscription/pkg/maven-org-mockito-mockito-core) Subscription. -The maintainers of org.mockito:mockito-core and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/maven-org-mockito-mockito-core?utm_source=maven-org-mockito-mockito-core&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) +The maintainers of org.mockito:mockito-core and thousands of other packages are working with Tidelift to deliver +commercial support and maintenance for the open source dependencies you use to build your applications. Save time, +reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. +[Learn more.](https://tidelift.com/subscription/pkg/maven-org-mockito-mockito-core?utm_source=maven-org-mockito-mockito-core&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) ## Development -Mockito [continuously delivers](https://github.com/mockito/mockito/wiki/Continuous-Delivery-Overview) improvements using Shipkit library (http://shipkit.org). See the [latest release notes](https://github.com/mockito/mockito/blob/release/3.x/doc/release-notes/official.md) and [latest documentation](http://javadoc.io/page/org.mockito/mockito-core/2/org/mockito/Mockito.html). Docs in javadoc.io are available 24h after release. Read also about [semantic versioning in Mockito](https://github.com/mockito/mockito/wiki/Semantic-Versioning). **Note: not every version is published to Maven Central.** +Mockito publishes every change as a `-SNAPSHOT` version to a public Sonatype repository. Roughly once a month, we +publish a new minor or patch version to Maven Central. For release automation we use +[Shipkit library](http://shipkit.org), [Gradle Nexus Publish Plugin](https://github.com/gradle-nexus/publish-plugin). +Fully automated releases are awesome, and you should do that for your libraries, too! +See the [latest release notes](https://github.com/mockito/mockito/releases/) +and [latest documentation](https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html). Docs in +javadoc.io are available 24h after release. Read also +about [semantic versioning in Mockito](https://github.com/mockito/mockito/wiki/Semantic-Versioning). Older 1.x and 2.x releases are available in -[Central Repository](http://search.maven.org/#artifactdetails|org.mockito|mockito-core|1.10.19|jar) -, [Bintray](https://bintray.com/mockito/maven/mockito/1.10.19/view) -and [javadoc.io](http://javadoc.io/doc/org.mockito/mockito-core/1.10.19/org/mockito/Mockito.html) (documentation). +[Central Repository](https://search.maven.org/artifact/org.mockito/mockito-core/1.10.19/jar) +and [javadoc.io](https://javadoc.io/doc/org.mockito/mockito-core/1.10.19/org/mockito/Mockito.html) (documentation). ## More information -All you want to know about Mockito is hosted at [The Mockito Site](http://site.mockito.org) which is [Open Source](https://github.com/mockito/mockito.github.io) and likes [pull requests](https://github.com/mockito/mockito.github.io/pulls), too. +All you want to know about Mockito is hosted at [The Mockito Site](https://site.mockito.org) which is [Open Source](https://github.com/mockito/mockito.github.io) and likes [pull requests](https://github.com/mockito/mockito.github.io/pulls), too. -Want to contribute? Take a look at the [Contributing Guide](https://github.com/mockito/mockito/blob/release/3.x/.github/CONTRIBUTING.md). +Want to contribute? Take a look at the [Contributing Guide](https://github.com/mockito/mockito/blob/main/.github/CONTRIBUTING.md). Enjoy Mockito! ## Need help? -* Search / Ask question on [stackoverflow](http://stackoverflow.com/questions/tagged/mockito) -* Go to the [mockito mailing-list](http://groups.google.com/group/mockito) (moderated) +* Search / Ask question on [stackoverflow](https://stackoverflow.com/questions/tagged/mockito) +* Go to the [mockito mailing-list](https://groups.google.com/group/mockito) (moderated) * Open a ticket in GitHub [issue tracker](https://github.com/mockito/mockito/issues) ## How to develop Mockito? To build locally: - ./gradlew build - -To develop in IntelliJ IDEA you can use built-in Gradle import wizard in IDEA. -Alternatively generate the importable IDEA metadata files using: - - ./gradlew idea - -Then, _open_ the generated *.ipr file in IDEA. +```shell +./gradlew build +``` +You can open in any IDE that support Gradle, e.g. IntelliJ IDEA, or Fleet. +For Eclipse, one may need to run `./gradlew eclipse` before importing the project. ## How to release new version? -Mockito [implements Continuous Delivery model](https://github.com/mockito/mockito/wiki/Continuous-Delivery-Overview). -Every change on main branch (for example merging a pull request) triggers a release build on Travis CI. -The build publishes new version if specific criteria are met: all tests green, no 'ci skip release' used in commit message, see the build log for more information. -Every new version is published to ["mockito/maven" Bintray repository](https://bintray.com/mockito/maven). -New versions that Mockito team deems "notable" are additionally published to [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.mockito%22) and [JCenter](https://bintray.com/bintray/jcenter). -We used to publish every version to Maven Central but we changed this strategy based on feedback from the community ([#911](https://github.com/mockito/mockito/issues/911)). - -* Q: What's new in Mockito release model? - - A: In Q2 2017 we implemented [Mockito Continuous Delivery Pipeline 2.0](https://github.com/mockito/mockito/issues/911). - Not every version is published to Maven Central. - -* Q: How to publish to Maven Central? - - A: Include "[ci maven-central-release]" in the **merge** commit when merging the PR. - **Hint**: To signify a new feature consider updating version to next minor/major, like: "2.8.0", "2.9.0", "3.0.0". +1. Every change on the main development branch is released as `-SNAPSHOT` version to Sonatype snapshot repo + at https://s01.oss.sonatype.org/content/repositories/snapshots/org/mockito/mockito-core. +2. To release a non-snapshot version to Maven Central push an annotated tag, for example: -* Q: How to promote already released version to a notable version? + ```shell + git tag -a -m "Release 3.4.5" v3.4.5 + git push origin v3.4.5 + ``` - A: It isn't automated at the moment. [What's the use case?](https://github.com/mockito/mockito/issues/911) +3. At the moment, you **may not create releases from GitHub Web UI**. Doing so will make the CI build fail because the + CI creates the changelog and posts to GitHub releases. We'll support this in the future. diff --git a/build.gradle b/build.gradle deleted file mode 100644 index a44878c0a9..0000000000 --- a/build.gradle +++ /dev/null @@ -1,134 +0,0 @@ -buildscript { - repositories { - mavenLocal() //for local testing of mockito-release-tools - jcenter() - maven { url "https://plugins.gradle.org/m2/" } - } - - dependencies { - classpath 'gradle.plugin.nl.javadude.gradle.plugins:license-gradle-plugin:0.14.0' - classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.6' - - //Using buildscript.classpath so that we can resolve shipkit from maven local, during local testing - classpath 'org.shipkit:shipkit:2.1.6' - } -} - -plugins { - id 'com.gradle.build-scan' version '2.2.1' - id "com.diffplug.gradle.spotless" version "3.24.3" - id 'eclipse' -} - -description = 'Mockito mock objects library core API and implementation' - -apply plugin: 'base' -archivesBaseName = "mockito-core" - -apply plugin: "org.shipkit.java" -allprojects { - plugins.withId("java") { - //Only upload specific modules we select - bintrayUpload.enabled = false - } -} - -apply from: 'gradle/root/ide.gradle' -apply from: 'gradle/root/gradle-fix.gradle' -apply from: 'gradle/java-library.gradle' -apply from: 'gradle/license.gradle' -apply from: 'gradle/root/coverage.gradle' - -apply from: 'gradle/mockito-core/inline-mock.gradle' -apply from: 'gradle/mockito-core/osgi.gradle' -apply from: 'gradle/mockito-core/javadoc.gradle' -apply from: 'gradle/mockito-core/testing.gradle' - -apply from: 'gradle/dependencies.gradle' - -allprojects { proj -> - repositories { - jcenter() - } - plugins.withId('java') { - proj.apply from: "$rootDir/gradle/errorprone.gradle" - } - tasks.withType(JavaCompile) { - //I don't believe those warnings add value given modern IDEs - options.warnings = false - options.encoding = 'UTF-8' - } - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - options.addStringOption('encoding', 'UTF-8') - options.addStringOption('charSet', 'UTF-8') - options.setSource('8') - } - apply plugin: 'checkstyle' - checkstyle { - configFile = rootProject.file('config/checkstyle/checkstyle.xml') - } -} - -configurations { - testUtil //TODO move to separate project -} - -dependencies { - compile libraries.bytebuddy, libraries.bytebuddyagent - - compileOnly libraries.junit4, libraries.hamcrest, libraries.opentest4j - compile libraries.objenesis - - testCompile libraries.asm - - testCompile libraries.assertj - - //putting 'provided' dependencies on test compile and runtime classpath - testCompileOnly configurations.compileOnly - testRuntime configurations.compileOnly - - testUtil sourceSets.test.output -} - -wrapper { - gradleVersion = '5.3.1' - distributionSha256Sum = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' -} - -//Posting Build scans to https://scans.gradle.com -buildScan { - termsOfServiceUrl = 'https://gradle.com/terms-of-service' - termsOfServiceAgree = 'yes' -} - -spotless { - java { - licenseHeaderFile rootProject.file('config/spotless/spotless.header') - - removeUnusedImports() - trimTrailingWhitespace() - endWithNewline() - indentWithSpaces(4) - - importOrder 'static java', 'static javax', 'static ', 'java', 'javax', '' - } -} - - -//workaround for #1444, delete when Shipkit bug is fixed -subprojects { - eclipse { - project { - name = rootProject.name + '-' + project.name - } - } - - afterEvaluate { - def lib = publishing.publications.javaLibrary - if(lib && !lib.artifactId.startsWith("mockito-")) { - lib.artifactId = "mockito-" + lib.artifactId - } - } -} -//end workaround diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000000..b5b00de8a0 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,22 @@ +buildscript { + repositories { + mavenLocal() //for local testing of mockito-release-tools + google() + gradlePluginPortal() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.24") + } +} + +plugins { + id("eclipse") + id("com.github.ben-manes.versions") version "0.51.0" + id("mockito.root.releasing-conventions") + + // Top-level android plugin declaration required for :mockito-integration-tests:android-tests to work + alias(libs.plugins.android.application) apply false +} + + diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000000..60cdda5b56 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + // doc: https://docs.gradle.org/current/userguide/kotlin_dsl.html + `kotlin-dsl` +} + +dependencies { + implementation(libs.gradleplugin.testLogger) + implementation(libs.gradleplugin.animalSniffer) + implementation(libs.gradleplugin.bnd) + implementation(libs.gradleplugin.errorprone) + implementation(libs.gradleplugin.spotless) + implementation(libs.gradleplugin.spotless.googleJavaFormat) + implementation(libs.gradleplugin.license) + + implementation(libs.gradleplugin.nexusPublish) + implementation(libs.gradleplugin.shipkit.changelog) + implementation(libs.gradleplugin.shipkit.autoVersion) + + // https://github.com/gradle/gradle/issues/15383 + implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) +} diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 0000000000..1a4794687b --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,11 @@ +dependencyResolutionManagement { + repositories { + mavenCentral() + gradlePluginPortal() + } + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} diff --git a/buildSrc/src/main/kotlin/Common.kt b/buildSrc/src/main/kotlin/Common.kt new file mode 100644 index 0000000000..d250678050 --- /dev/null +++ b/buildSrc/src/main/kotlin/Common.kt @@ -0,0 +1,10 @@ +import org.gradle.accessors.dm.LibrariesForLibs +import org.gradle.api.Project +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.kotlin.dsl.the + +val Project.libs + get() = the() + +val Project.sourceSets + get() = the() diff --git a/buildSrc/src/main/kotlin/MockitoJavadoc.kt b/buildSrc/src/main/kotlin/MockitoJavadoc.kt new file mode 100644 index 0000000000..46fa27446a --- /dev/null +++ b/buildSrc/src/main/kotlin/MockitoJavadoc.kt @@ -0,0 +1,6 @@ +import org.gradle.api.provider.Property + +interface MockitoJavadocExtension { + val title: Property + val docTitle: Property +} diff --git a/buildSrc/src/main/kotlin/TaskExtensions.kt b/buildSrc/src/main/kotlin/TaskExtensions.kt new file mode 100644 index 0000000000..50331722aa --- /dev/null +++ b/buildSrc/src/main/kotlin/TaskExtensions.kt @@ -0,0 +1,7 @@ +import org.gradle.api.tasks.javadoc.Javadoc +import org.gradle.external.javadoc.StandardJavadocDocletOptions + +/** Applies the standard doclet options. */ +fun Javadoc.javadocDocletOptions(block: StandardJavadocDocletOptions.() -> Unit) { + (options as StandardJavadocDocletOptions).apply(block) +} diff --git a/buildSrc/src/main/kotlin/mockito.java-backward-compatibility-checks-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.java-backward-compatibility-checks-conventions.gradle.kts new file mode 100644 index 0000000000..d19efc6644 --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.java-backward-compatibility-checks-conventions.gradle.kts @@ -0,0 +1,30 @@ +import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension + +plugins { + java // for sourceSets + id("ru.vyarus.animalsniffer") +} + + +val main: SourceSet by sourceSets.getting +configure { + sourceSets = listOf(main) + annotation = "org.mockito.internal.SuppressSignatureCheck" + + // See please https://github.com/mojohaus/animal-sniffer/issues/172 + ignore( + "java.lang.instrument.Instrumentation", + "java.lang.invoke.MethodHandle", + "java.lang.invoke.MethodHandles\$Lookup", + "java.lang.StackWalker", + "java.lang.StackWalker\$StackFrame", + "java.lang.StackWalker\$Option", + ) +} + +dependencies { + // Equivalent to "net.sf.androidscents.signature:android-api-level-26:8.0.0_r2@signature" + signature(variantOf(libs.animalSniffer.android.apiLevel26) { artifactType("signature") }) + signature(variantOf(libs.animalSniffer.java) { artifactType("signature") }) +} + diff --git a/buildSrc/src/main/kotlin/mockito.java-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.java-conventions.gradle.kts new file mode 100644 index 0000000000..1e41ef22d7 --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.java-conventions.gradle.kts @@ -0,0 +1,34 @@ +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.plugins.JavaPluginExtension + +// only apply to Java projects +// i.e., do nothing when applied to Android projects +plugins.withType(JavaPlugin::class) { + val javaReleaseVersion = 11 + + configure { + sourceCompatibility = JavaVersion.toVersion(javaReleaseVersion) + targetCompatibility = JavaVersion.toVersion(javaReleaseVersion) + } + + tasks { + withType().configureEach { + // I don't believe those warnings add value given modern IDEs + options.isWarnings = false + options.encoding = "UTF-8" + } + + withType().configureEach { + options { + encoding = "UTF-8" + source = javaReleaseVersion.toString() + + if (this is StandardJavadocDocletOptions) { + addStringOption("Xdoclint:none", "-quiet") + addStringOption("charSet", "UTF-8") + } + } + } + } +} + diff --git a/buildSrc/src/main/kotlin/mockito.java-library-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.java-library-conventions.gradle.kts new file mode 100644 index 0000000000..40633ea36d --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.java-library-conventions.gradle.kts @@ -0,0 +1,36 @@ +plugins { + `java-library` + id("mockito.java-conventions") + id("mockito.test-conventions") + id("mockito.test-retry-conventions") + id("mockito.test-launcher-conventions") + id("net.ltgt.errorprone") +} + +if (!project.name.startsWith("mockito-")) { + throw GradleException("Published project module should be prefixed with `mockito-` : ${project.projectDir})") +} + +repositories { + mavenCentral() + google() +} + +dependencies { + errorprone(libs.errorprone) +} + +tasks { + withType().configureEach { + isPreserveFileTimestamps = false + isReproducibleFileOrder = true + // dirMode = Integer.parseInt("0755", 8) + dirPermissions { + unix("rwxr-xr-x") // 0755 + } + // fileMode = Integer.parseInt("0644", 8) + filePermissions { + unix("rw-r--r--") // 0644 + } + } +} diff --git a/buildSrc/src/main/kotlin/mockito.javadoc-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.javadoc-conventions.gradle.kts new file mode 100644 index 0000000000..29aab3a9dd --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.javadoc-conventions.gradle.kts @@ -0,0 +1,69 @@ +import org.gradle.api.tasks.javadoc.Javadoc + +plugins { + java +} + +val mockitoJavadocExtension = project.extensions.create("mockitoJavadoc").apply { + title.convention(project.name) + docTitle.convention("

${project.name}

") +} + +val javadocConfigDir = "$rootDir/config/javadoc" + +tasks.named("javadoc") { + inputs.dir(javadocConfigDir) + description = "Creates javadoc html for ${project.name}." + + // Work-around as suggested in https://github.com/gradle/gradle/issues/19726 + val sourceSetDirectories = sourceSets.main.get().java.sourceDirectories.joinToString(":") + val coreOptions = options as CoreJavadocOptions + coreOptions.addStringOption("-source-path", sourceSetDirectories) + exclude("**/internal/**") + + // For more details on the format + // see https://docs.oracle.com/en/java/javase/21/javadoc/javadoc.html + options { + title = mockitoJavadocExtension.title.get() + encoding = "UTF-8" + + if (this is StandardJavadocDocletOptions) { + addBooleanOption("-allow-script-in-comments", true) + addFileOption("-add-stylesheet", project.file("$javadocConfigDir/resources/mockito-theme.css")) + addStringOption("Xwerror", "-quiet") + charSet = "UTF-8" + docEncoding = "UTF-8" + docTitle = mockitoJavadocExtension.docTitle.get() + + bottom( + """ + + + + """.trimIndent().replace("\r|\n|[ ]{8}".toRegex(), "") + ) + + group("Main package", "org.mockito") + links("https://junit.org/junit4/javadoc/${project.libs.versions.junit4.get()}/") + linksOffline( + "https://docs.oracle.com/en/java/javase/11/docs/api/", + "$javadocConfigDir/jdk-package-list" + ) + + isSplitIndex = true + isUse = true + windowTitle = mockitoJavadocExtension.title.get() + + addBooleanOption("html5", true) + } + memberLevel = JavadocMemberLevel.PROTECTED + outputLevel = JavadocOutputLevel.QUIET + } + + doLast { + copy { + from("$javadocConfigDir/resources") + into(destinationDir!!) + } + } +} diff --git a/buildSrc/src/main/kotlin/mockito.library-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.library-conventions.gradle.kts new file mode 100644 index 0000000000..09049d6282 --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.library-conventions.gradle.kts @@ -0,0 +1,9 @@ +plugins { + base + id("mockito.java-library-conventions") + id("mockito.osgi-conventions") + id("mockito.publication-conventions") + id("mockito.quality-checkstyle-conventions") + id("mockito.quality-spotless-conventions") + id("mockito.license-conventions") +} diff --git a/buildSrc/src/main/kotlin/mockito.license-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.license-conventions.gradle.kts new file mode 100644 index 0000000000..247caf88af --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.license-conventions.gradle.kts @@ -0,0 +1,29 @@ +import java.time.OffsetDateTime +import java.time.ZoneOffset + +plugins { + id("com.github.hierynomus.license") +} + +val licenseHeaderFile = rootProject.file("doc/licenses/HEADER.txt") + +license { + header = licenseHeaderFile + strictCheck = true + ignoreFailures = true + skipExistingHeaders = true + mapping(mapOf( + "java" to "SLASHSTAR_STYLE", + "groovy" to "SLASHSTAR_STYLE", + "kt" to "SLASHSTAR_STYLE", + )) + + exclude("junit-platform.properties") + exclude("mockito-extensions/org.mockito.plugins.*") + exclude("META-INF/services/org.junit.jupiter.api.extension.Extension") + exclude("org/mockito/internal/util/concurrent/README.md") + exclude("org/mockito/internal/util/concurrent/LICENSE") + + + ext["year"] = OffsetDateTime.now(ZoneOffset.UTC).year +} diff --git a/buildSrc/src/main/kotlin/mockito.osgi-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.osgi-conventions.gradle.kts new file mode 100644 index 0000000000..eaa8a3ed92 --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.osgi-conventions.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("biz.aQute.bnd.builder") +} diff --git a/buildSrc/src/main/kotlin/mockito.publication-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.publication-conventions.gradle.kts new file mode 100644 index 0000000000..de2f6ac5d9 --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.publication-conventions.gradle.kts @@ -0,0 +1,166 @@ +import org.gradle.kotlin.dsl.`maven-publish` +import org.gradle.kotlin.dsl.withType + +plugins { + `maven-publish` + signing +} + +// enforce the same group for all published artifacts +group = "org.mockito" + +val localRepoForTesting = rootProject.layout.buildDirectory.dir("repo") + +// generic publication conventions +publishing { + publications { + withType(MavenPublication::class).configureEach { + pom { + artifactId = project.base.archivesName.get() + name = artifactId + description = providers.provider { project.description } + url = "https://github.com/mockito/mockito" + licenses { + license { + name = "MIT" + url = "https://opensource.org/licenses/MIT" + distribution = "repo" + } + } + developers { + listOf( + "mockitoguy:Szczepan Faber", + "bric3:Brice Dutheil", + "raphw:Rafael Winterhalter", + "TimvdLippe:Tim van der Lippe" + ).forEach { devData -> + developer { + val devInfo = devData.split(":") + id = devInfo[0] + name = devInfo[1] + url = "https://github.com/" + devInfo[0] + roles = listOf("Core developer") + } + } + } + scm { + url = "https://github.com/mockito/mockito.git" + } + issueManagement { + url = "https://github.com/mockito/mockito/issues" + system = "GitHub issues" + } + ciManagement { + url = "https://github.com/mockito/mockito/actions" + system = "GH Actions" + } + } + } + } + + //useful for testing - running "publish" will create artifacts/pom in a local dir + repositories { + maven(uri(localRepoForTesting)) { + name = "local" + } + } +} + +tasks.clean { + doLast { + delete(localRepoForTesting) + } +} + +// Java platform publication conventions (BOM file) +plugins.withType(JavaPlatformPlugin::class) { + publishing { + publications { + register("mockitoPlatform") { + from(components["javaPlatform"]) + } + } + } +} + +// Java library publication conventions +plugins.withType().configureEach { + // Sources/javadoc artifacts required by Maven module publications + val licenseSpec = copySpec { + from(project.rootDir) + include("LICENSE") + } + + val sourcesJar by tasks.registering(Jar::class) { + archiveClassifier.set("sources") + from(project.sourceSets["main"].allSource) + with(licenseSpec) + } + + val javadocJar by tasks.registering(Jar::class) { + archiveClassifier.set("javadoc") + from(tasks.named("javadoc")) + with(licenseSpec) + } + + project.artifacts { + archives(sourcesJar) + archives(javadocJar) + } + + tasks.named("jar", Jar::class) { + with(licenseSpec) + } + + // only create a 'java' publication when the JavaPlugin is present + publishing { + publications { + register("mockitoLibrary") { + from(components["java"]) + artifact(sourcesJar) + artifact(javadocJar) + + pom { + // Gradle does not write 'jar' packaging to the pom (unlike other packaging types). + // This is OK because 'jar' is implicit/default: + // https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#minimal-pom + packaging = project.tasks.named("jar").get().archiveExtension.get() + } + } + } + } + + tasks.named("generatePomFileForMockitoLibraryPublication") { + doLast { + // validates that the pom has correct artifact id to avoid issues like #1444 + destination.readText().let { pomContent -> + require(pomContent.contains("${project.base.archivesName.get()}")) { + "POM file does not contain the correct artifactId: ${project.base.archivesName.get()}" + } + require(pomContent.contains("${project.base.archivesName.get()}")) { + "POM file does not contain the correct name: ${project.base.archivesName.get()}" + } + } + } + } + + // fleshes out problems with Maven pom generation when building + tasks.build { + dependsOn("publishAllPublicationsToLocalRepository") + } +} + +tasks.withType().configureEach { + enabled = false +} + +// https://docs.gradle.org/current/userguide/signing_plugin.html +signing { + if (providers.environmentVariable("PGP_KEY").isPresent) { + useInMemoryPgpKeys( + providers.environmentVariable("PGP_KEY").orNull, + providers.environmentVariable("PGP_PWD").orNull + ) + sign(publishing.publications) + } +} diff --git a/buildSrc/src/main/kotlin/mockito.quality-checkstyle-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.quality-checkstyle-conventions.gradle.kts new file mode 100644 index 0000000000..3fda6bd2cb --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.quality-checkstyle-conventions.gradle.kts @@ -0,0 +1,19 @@ +import org.gradle.api.plugins.quality.Checkstyle +import org.gradle.kotlin.dsl.checkstyle +import org.gradle.kotlin.dsl.withType + +plugins { + checkstyle +} + +checkstyle { + configFile = rootProject.file("config/checkstyle/checkstyle.xml") +} + +tasks.withType().configureEach { + reports { + xml.required.set(false) + html.required.set(true) + html.stylesheet = resources.text.fromFile("$rootDir/config/checkstyle/checkstyle.xsl") + } +} diff --git a/buildSrc/src/main/kotlin/mockito.quality-spotless-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.quality-spotless-conventions.gradle.kts new file mode 100644 index 0000000000..5f896044fc --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.quality-spotless-conventions.gradle.kts @@ -0,0 +1,46 @@ +import com.diffplug.gradle.spotless.SpotlessExtension +import com.diffplug.spotless.FormatterFunc +import com.google.googlejavaformat.java.Formatter +import com.google.googlejavaformat.java.JavaFormatterOptions +import java.io.Serializable + +plugins { + id("com.diffplug.spotless") +} + +configure { + // We run the check separately on CI, so don't run this by default + isEnforceCheck = false + + java { + licenseHeaderFile(rootProject.file("config/spotless/spotless.header")) + + // Not using stock googleJavaFormat due to missing options like reorderModifiers + // Also, using the Serializable interface to work around bug in spotless 7.0.0 + // https://github.com/diffplug/spotless/issues/2387 + custom("google-java-format", object : Serializable, FormatterFunc { + override fun apply(input: String): String { + val formatterOptions = JavaFormatterOptions.builder() + .style(JavaFormatterOptions.Style.AOSP) + .reorderModifiers(true) + .formatJavadoc(false) + .build() + + return Formatter(formatterOptions).formatSource(input) + } + }) + + toggleOffOn() + } + + format("misc") { + target( + "*.gradle", + "*.gradle.kts", + ".gitignore", + ) + targetExclude("**/build/") + trimTrailingWhitespace() + } +} + diff --git a/buildSrc/src/main/kotlin/mockito.root.releasing-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.root.releasing-conventions.gradle.kts new file mode 100644 index 0000000000..b7d77b024a --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.root.releasing-conventions.gradle.kts @@ -0,0 +1,75 @@ +plugins { + id("org.shipkit.shipkit-auto-version") + id("org.shipkit.shipkit-changelog") + id("org.shipkit.shipkit-github-release") + + id("io.github.gradle-nexus.publish-plugin") +} + +val isSnapshot = version.toString().endsWith("SNAPSHOT") +val githubTokenProvider = providers.environmentVariable("GITHUB_TOKEN").orElse("") +val githubShaProvider = providers.environmentVariable("GITHUB_SHA").orElse("") +val mockitoRepository = "mockito/mockito" + +tasks { + generateChangelog { + githubToken = githubTokenProvider.get() + previousRevision = project.ext["shipkit-auto-version.previous-tag"].toString() + repository = mockitoRepository + } + + githubRelease { + enabled = !isSnapshot + dependsOn(generateChangelog) + githubToken = githubTokenProvider.get() + newTagRevision = githubShaProvider.get() + repository = mockitoRepository + changelog = generateChangelog.get().outputFile + } + + closeAndReleaseStagingRepositories { + enabled = !isSnapshot + } + + val releaseSummary by registering { + doLast { + if (isSnapshot) { + logger.lifecycle( + """ + RELEASE SUMMARY + SNAPSHOTS released to: https://s01.oss.sonatype.org/content/repositories/snapshots/org/mockito/mockito-core + Release to Maven Central: SKIPPED FOR SNAPSHOTS + Github releases: SKIPPED FOR SNAPSHOTS + """.trimIndent() + ) + } else { + logger.lifecycle( + """ + RELEASE SUMMARY + Release to Maven Central (available in few hours): https://repo1.maven.org/maven2/org/mockito/mockito-core/ + Github releases: https://github.com/mockito/mockito/releases + """.trimIndent() + ) + } + } + } +} + +nexusPublishing { + packageGroup = "org.mockito" + repositoryDescription = provider { "Mockito ${project.version}" } + + repositories { + if (!providers.environmentVariable("NEXUS_TOKEN_PWD").orNull.isNullOrBlank()) { + sonatype { + // Publishing to: https://s01.oss.sonatype.org (faster instance) + nexusUrl = uri("https://s01.oss.sonatype.org/service/local/") + snapshotRepositoryUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") + + username = providers.environmentVariable("NEXUS_TOKEN_USER") + password = providers.environmentVariable("NEXUS_TOKEN_PWD") + } + } + } +} + diff --git a/buildSrc/src/main/kotlin/mockito.test-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.test-conventions.gradle.kts new file mode 100644 index 0000000000..1c1541d031 --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.test-conventions.gradle.kts @@ -0,0 +1,33 @@ +import com.adarshr.gradle.testlogger.theme.ThemeType + +plugins { + id("mockito.java-conventions") + id("com.adarshr.test-logger") + id("mockito.quality-spotless-conventions") + id("mockito.license-conventions") +} + +repositories { + mavenCentral() + google() +} + +testlogger { + theme = ThemeType.MOCHA_PARALLEL + isShowPassed = false +} + +tasks { + // Configure the main "test" task for `java` only projects. + plugins.withType(JavaPlugin::class) { + named("test") { + // This ignores classes with JUnit annotations not ending with "Test" + include("**/*Test.class") + + if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17) + && providers.environmentVariable("MEMBER_ACCESSOR").orNull == "member-accessor-reflection") { + jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") + } + } + } +} diff --git a/buildSrc/src/main/kotlin/mockito.test-jfr-profiling-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.test-jfr-profiling-conventions.gradle.kts new file mode 100644 index 0000000000..d3edda47a5 --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.test-jfr-profiling-conventions.gradle.kts @@ -0,0 +1,34 @@ +plugins.withType(JavaPlugin::class) { + tasks.withType().configureEach { + val taskName = name + /* + * If the gradle option -Pjfr is set during test execution, JFR will be activated for that execution. + */ + if (project.extensions.extraProperties.has("jfr")) { + val jfrDir = "build/jfr" + val jfrConfigFile = rootProject.file("config/jfr/jfr_config.jfc") + val jfrFile = project.file("$jfrDir/${taskName}_Exec.jfr") + + jvmArgs( + //https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html + // Search for -XX:FlightRecorderOptions and -XX:StartFlightRecording for more details in the documentation + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+DebugNonSafepoints", + "-XX:FlightRecorderOptions=stackdepth=1024", + "-XX:StartFlightRecording=name=TestExec_$taskName,disk=true,maxsize=1g,dumponexit=true,filename=$jfrFile,settings=${jfrConfigFile.absolutePath}") + + //We do not want to be UP-TO-DATE, if we are doing a Java Flight Recording. We always want a new recording. + outputs.upToDateWhen { false } + + doFirst { + //Ensure that the jfr folder exists, otherwise the Java process start will fail. + project.file(jfrDir).mkdirs() + } + + doLast{ + logger.lifecycle("Java Flight Recording was written to: $jfrFile") + } + } + } +} + diff --git a/buildSrc/src/main/kotlin/mockito.test-launcher-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.test-launcher-conventions.gradle.kts new file mode 100644 index 0000000000..8c4d6c487f --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.test-launcher-conventions.gradle.kts @@ -0,0 +1,18 @@ +plugins { + `jvm-toolchains` +} + +tasks.withType { + // Apply the CI test launcher configuration to any test tasks. + javaLauncher = javaToolchains.launcherFor { + languageVersion = providers + .gradleProperty("mockito.test.java") + .map { + if (it == "auto") { + JavaLanguageVersion.of(JavaVersion.current().majorVersion) + } else { + JavaLanguageVersion.of(it) + } + } + } +} diff --git a/buildSrc/src/main/kotlin/mockito.test-retry-conventions.gradle.kts b/buildSrc/src/main/kotlin/mockito.test-retry-conventions.gradle.kts new file mode 100644 index 0000000000..10ea2b2390 --- /dev/null +++ b/buildSrc/src/main/kotlin/mockito.test-retry-conventions.gradle.kts @@ -0,0 +1,86 @@ +import java.util.concurrent.ConcurrentSkipListSet + +plugins { + java +} + +/* + Plugin that retries failed tests. + Mockito has concurrent API and those tests and inherently flaky. + We decided to use retries to stabilize (conscious team choice) + Long term, we can evolve retry-test script plugin to a binary plugin or make it more robust + + Plugin adds 'retryTest' task that runs tests that failed during the execution of 'test' task. +*/ +tasks { + val retryTest by registering(Test::class) { + description = "Retries failed tests (if present)" + outputs.upToDateWhen { false } //we want to always run flaky tests because they are flaky + isEnabled = false // toggled on by `test` task if there are failed tests + + // re-use same parameters + testClassesDirs = test.map { it.testClassesDirs }.get() + classpath = test.map { it.classpath }.get() + isScanForTestClasses = test.map { it.isScanForTestClasses }.get() + include(test.map { it.includes }.get()) + + // logging handled by test-logger plugin + + doFirst { + logger.lifecycle("[retryTest] retrying ${filter.includePatterns.size} test(s).") + } + addTestListener(object : TestListener { + override fun beforeSuite(suite: TestDescriptor) {} + override fun beforeTest(testDescriptor: TestDescriptor) {} + override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) {} + override fun afterSuite(descriptor: TestDescriptor, result: TestResult) { + descriptor.parent ?: return // root + if (result.failedTestCount > 0) { + logger.lifecycle("\n[retryTest] retried ${filter.includePatterns.size} test(s), $result.failedTestCount still failed.") + } else { + logger.lifecycle("\n[retryTest] ${filter.includePatterns.size} test(s) were retried successfully:\n ${filter.includePatterns.joinToString("\n ")}") + } + } + }) + } + + test { + finalizedBy(retryTest) + val failedTests = ConcurrentSkipListSet() + + addTestListener(object : TestListener { + override fun beforeSuite(suite: TestDescriptor) {} + override fun beforeTest(testDescriptor: TestDescriptor) {} + + override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) { + if (!testDescriptor.isComposite /* e.g. is not a parent */ && result.failedTestCount > 0) { + //adding fully qualified test name, dropping "()" from the method name + failedTests.add("${testDescriptor.className}.${testDescriptor.name.replace("\\(\\)", "")}") + } + } + + override fun afterSuite(descriptor: TestDescriptor, result: TestResult) { + descriptor.parent ?: return // root + val failuresReport = layout.buildDirectory.file("$name-failures.txt").get().asFile + val deletion = !failuresReport.exists() || failuresReport.delete() + + val reportPath = rootProject.relativePath(failuresReport) + if (!deletion) { + throw GradleException("Problems deleting failures file: $reportPath. Please delete manually and retry.") + } + + if (failedTests.isNotEmpty()) { + failuresReport.writeText(failedTests.joinToString("\n")) + logger.lifecycle("\n[retryTest] wrote ${failedTests.size} failed tests to: $reportPath") + logger.info("[retryTest] all failed tests:\n ${failedTests.joinToString("\n ")}") + retryTest.get().isEnabled = true + retryTest.get().filter.setIncludePatterns(*failedTests.toTypedArray()) + ignoreFailures = true + } else { + logger.info("\n[retryTest] There are no failed tests, '$reportPath' file was deleted (if it existed).") + } + } + }) + } +} + diff --git a/check_reproducibility.sh b/check_reproducibility.sh new file mode 100755 index 0000000000..d4aab96f6c --- /dev/null +++ b/check_reproducibility.sh @@ -0,0 +1,26 @@ +#!/bin/bash -e + +# This script is taken from https://github.com/junit-team/junit5/pull/2217 + +rm -rf checksums/ +mkdir checksums/ + +export SOURCE_DATE_EPOCH=$(date +%s) + +function calculate_checksums() { + OUTPUT=checksums/$1 + + ./gradlew --no-build-cache clean assemble + + find ./build -name '*.jar' \ + | grep '/build/libs/' \ + | grep --invert-match 'javadoc' \ + | sort \ + | xargs sha256sum > ${OUTPUT} +} + + +calculate_checksums checksums-1.txt +calculate_checksums checksums-2.txt + +diff checksums/checksums-1.txt checksums/checksums-2.txt diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 2a5094bcda..c38f152429 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -1,7 +1,7 @@ + "https://checkstyle.org/dtds/configuration_1_2.dtd"> + + + @@ -28,8 +31,7 @@ - + - diff --git a/config/javadoc/jdk-package-list/element-list b/config/javadoc/jdk-package-list/element-list new file mode 100644 index 0000000000..4cfabf8fdf --- /dev/null +++ b/config/javadoc/jdk-package-list/element-list @@ -0,0 +1,282 @@ +module:java.base +java.io +java.lang +java.lang.annotation +java.lang.invoke +java.lang.module +java.lang.ref +java.lang.reflect +java.math +java.net +java.net.spi +java.nio +java.nio.channels +java.nio.channels.spi +java.nio.charset +java.nio.charset.spi +java.nio.file +java.nio.file.attribute +java.nio.file.spi +java.security +java.security.acl +java.security.cert +java.security.interfaces +java.security.spec +java.text +java.text.spi +java.time +java.time.chrono +java.time.format +java.time.temporal +java.time.zone +java.util +java.util.concurrent +java.util.concurrent.atomic +java.util.concurrent.locks +java.util.function +java.util.jar +java.util.regex +java.util.spi +java.util.stream +java.util.zip +javax.crypto +javax.crypto.interfaces +javax.crypto.spec +javax.net +javax.net.ssl +javax.security.auth +javax.security.auth.callback +javax.security.auth.login +javax.security.auth.spi +javax.security.auth.x500 +javax.security.cert +module:java.compiler +javax.annotation.processing +javax.lang.model +javax.lang.model.element +javax.lang.model.type +javax.lang.model.util +javax.tools +module:java.datatransfer +java.awt.datatransfer +module:java.desktop +java.applet +java.awt +java.awt.color +java.awt.desktop +java.awt.dnd +java.awt.event +java.awt.font +java.awt.geom +java.awt.im +java.awt.im.spi +java.awt.image +java.awt.image.renderable +java.awt.print +java.beans +java.beans.beancontext +javax.accessibility +javax.imageio +javax.imageio.event +javax.imageio.metadata +javax.imageio.plugins.bmp +javax.imageio.plugins.jpeg +javax.imageio.plugins.tiff +javax.imageio.spi +javax.imageio.stream +javax.print +javax.print.attribute +javax.print.attribute.standard +javax.print.event +javax.sound.midi +javax.sound.midi.spi +javax.sound.sampled +javax.sound.sampled.spi +javax.swing +javax.swing.border +javax.swing.colorchooser +javax.swing.event +javax.swing.filechooser +javax.swing.plaf +javax.swing.plaf.basic +javax.swing.plaf.metal +javax.swing.plaf.multi +javax.swing.plaf.nimbus +javax.swing.plaf.synth +javax.swing.table +javax.swing.text +javax.swing.text.html +javax.swing.text.html.parser +javax.swing.text.rtf +javax.swing.tree +javax.swing.undo +module:java.instrument +java.lang.instrument +module:java.logging +java.util.logging +module:java.management +java.lang.management +javax.management +javax.management.loading +javax.management.modelmbean +javax.management.monitor +javax.management.openmbean +javax.management.relation +javax.management.remote +javax.management.timer +module:java.management.rmi +javax.management.remote.rmi +module:java.naming +javax.naming +javax.naming.directory +javax.naming.event +javax.naming.ldap +javax.naming.spi +module:java.net.http +java.net.http +module:java.prefs +java.util.prefs +module:java.rmi +java.rmi +java.rmi.activation +java.rmi.dgc +java.rmi.registry +java.rmi.server +javax.rmi.ssl +module:java.scripting +javax.script +module:java.se +module:java.security.jgss +javax.security.auth.kerberos +org.ietf.jgss +module:java.security.sasl +javax.security.sasl +module:java.smartcardio +javax.smartcardio +module:java.sql +java.sql +javax.sql +module:java.sql.rowset +javax.sql.rowset +javax.sql.rowset.serial +javax.sql.rowset.spi +module:java.transaction.xa +javax.transaction.xa +module:java.xml +javax.xml +javax.xml.catalog +javax.xml.datatype +javax.xml.namespace +javax.xml.parsers +javax.xml.stream +javax.xml.stream.events +javax.xml.stream.util +javax.xml.transform +javax.xml.transform.dom +javax.xml.transform.sax +javax.xml.transform.stax +javax.xml.transform.stream +javax.xml.validation +javax.xml.xpath +org.w3c.dom +org.w3c.dom.bootstrap +org.w3c.dom.events +org.w3c.dom.ls +org.w3c.dom.ranges +org.w3c.dom.traversal +org.w3c.dom.views +org.xml.sax +org.xml.sax.ext +org.xml.sax.helpers +module:java.xml.crypto +javax.xml.crypto +javax.xml.crypto.dom +javax.xml.crypto.dsig +javax.xml.crypto.dsig.dom +javax.xml.crypto.dsig.keyinfo +javax.xml.crypto.dsig.spec +module:jdk.accessibility +com.sun.java.accessibility.util +module:jdk.attach +com.sun.tools.attach +com.sun.tools.attach.spi +module:jdk.charsets +module:jdk.compiler +com.sun.source.doctree +com.sun.source.tree +com.sun.source.util +com.sun.tools.javac +module:jdk.crypto.cryptoki +module:jdk.crypto.ec +module:jdk.dynalink +jdk.dynalink +jdk.dynalink.beans +jdk.dynalink.linker +jdk.dynalink.linker.support +jdk.dynalink.support +module:jdk.editpad +module:jdk.hotspot.agent +module:jdk.httpserver +com.sun.net.httpserver +com.sun.net.httpserver.spi +module:jdk.jartool +com.sun.jarsigner +jdk.security.jarsigner +module:jdk.javadoc +com.sun.javadoc +com.sun.tools.javadoc +jdk.javadoc.doclet +module:jdk.jcmd +module:jdk.jconsole +com.sun.tools.jconsole +module:jdk.jdeps +module:jdk.jdi +com.sun.jdi +com.sun.jdi.connect +com.sun.jdi.connect.spi +com.sun.jdi.event +com.sun.jdi.request +module:jdk.jdwp.agent +module:jdk.jfr +jdk.jfr +jdk.jfr.consumer +module:jdk.jlink +module:jdk.jshell +jdk.jshell +jdk.jshell.execution +jdk.jshell.spi +jdk.jshell.tool +module:jdk.jsobject +netscape.javascript +module:jdk.jstatd +module:jdk.localedata +module:jdk.management +com.sun.management +module:jdk.management.agent +module:jdk.management.jfr +jdk.management.jfr +module:jdk.naming.dns +module:jdk.naming.rmi +module:jdk.net +jdk.net +jdk.nio +module:jdk.pack +module:jdk.rmic +module:jdk.scripting.nashorn +jdk.nashorn.api.scripting +jdk.nashorn.api.tree +module:jdk.sctp +com.sun.nio.sctp +module:jdk.security.auth +com.sun.security.auth +com.sun.security.auth.callback +com.sun.security.auth.login +com.sun.security.auth.module +module:jdk.security.jgss +com.sun.security.jgss +module:jdk.xml.dom +org.w3c.dom.css +org.w3c.dom.html +org.w3c.dom.stylesheets +org.w3c.dom.xpath +module:jdk.zipfs diff --git a/src/javadoc/favicon.ico b/config/javadoc/resources/favicon.ico similarity index 100% rename from src/javadoc/favicon.ico rename to config/javadoc/resources/favicon.ico diff --git a/config/javadoc/resources/mockito-theme.css b/config/javadoc/resources/mockito-theme.css new file mode 100644 index 0000000000..69f4ab5add --- /dev/null +++ b/config/javadoc/resources/mockito-theme.css @@ -0,0 +1,13 @@ +:root { + /* Text colors for body and block elements */ + --body-text-color: #333333; + /* Colors for navigation bar and table captions */ + --navbar-background-color: #474747; + /* Background and text colors for selected tabs and navigation items */ + --selected-background-color: #EAF9DD; + /* Text color for page title */ + --title-color: #333333; + /* Text colors for links */ + --link-color: #333333; + --link-color-active: #82a54d; +} diff --git a/src/javadoc/org/mockito/logo.png b/config/javadoc/resources/org/mockito/logo.png similarity index 100% rename from src/javadoc/org/mockito/logo.png rename to config/javadoc/resources/org/mockito/logo.png diff --git a/src/javadoc/org/mockito/logo@2x.png b/config/javadoc/resources/org/mockito/logo@2x.png similarity index 100% rename from src/javadoc/org/mockito/logo@2x.png rename to config/javadoc/resources/org/mockito/logo@2x.png diff --git a/config/jfr/jfr_config.jfc b/config/jfr/jfr_config.jfc new file mode 100644 index 0000000000..eae0a621e1 --- /dev/null +++ b/config/jfr/jfr_config.jfc @@ -0,0 +1,836 @@ + + + + + true + everyChunk + + + + true + 1000 ms + + + + true + everyChunk + + + + true + 1000 ms + + + + true + 10 s + + + + true + 10 s + + + + true + 10 s + + + + true + 10 s + + + + true + 10 s + + + + true + true + + + + true + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + true + + + + false + true + 0 ms + + + + false + true + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + + + + false + + + + true + beginChunk + + + + true + beginChunk + + + + true + 2 ms + + + + true + 20 ms + + + + true + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + true + 0 ms + + + + true + true + + + + true + 10 s + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + false + everyChunk + + + + true + everyChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + false + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + true + + + + true + true + + + + true + + + + true + 0 ms + + + + true + 0 ms + true + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + 0 ms + + + + true + + + + true + + + + true + + + + true + + + + true + + + + false + true + + + + true + + + + false + everyChunk + + + + false + + + + false + everyChunk + + + + false + + + + true + true + 0 ns + + + + true + beginChunk + + + + true + 1000 ms + + + + true + 100 ms + + + + true + 10 s + + + + true + + + + true + + + + true + + + + true + beginChunk + + + + true + everyChunk + + + + true + 100 ms + + + + true + beginChunk + + + + true + everyChunk + + + + true + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + 30 s + + + + true + 30 s + + + + true + 30 s + + + + true + 30 s + + + + true + beginChunk + + + + true + 10 s + + + + true + 1000 ms + + + + true + 10 s + + + + true + beginChunk + + + + true + endChunk + + + + true + true + + + + true + 5 s + + + + true + beginChunk + + + + true + everyChunk + + + + true + true + + + + true + true + + + + true + 1000/s + true + + + + true + everyChunk + + + + true + endChunk + + + + true + endChunk + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + false + true + + + + true + beginChunk + + + + false + true + + + + false + true + + + + false + true + + + + false + true + + + + false + true + + + + true + true + + + + true + true + + + + true + 1000 ms + + + + true + + + + true + + + + false + 0 ns + + + + true + + + + true + + + + true + 0 ms + + + + true + true + 1 ms + + + + true + 0 ms + + + + true + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + true + + + + true + 0 ns + true + + + + true + 5 s + + + + true + 100 ms + true + + + diff --git a/doc/release-notes/official.md b/doc/release-notes/official.md index a9d866e818..edae708fe3 100644 --- a/doc/release-notes/official.md +++ b/doc/release-notes/official.md @@ -1,4 +1,212 @@ -*Release notes were automatically generated by [Shipkit](http://shipkit.org/)* +# Deprecated + +As of Oct 2020, this file is no longer updated. +The most current Mockito changelog is automatically generated to [GitHub Releases](https://github.com/mockito/mockito/releases). +The generation is implemented using https://shipkit.org. + +# Old release notes + +#### 3.6.0 + - 2020-10-27 - [7 commits](https://github.com/mockito/mockito/compare/v3.5.15...v3.6.0) by [Szczepan Faber](https://github.com/mockitoguy) (4), [shipkit-org](https://github.com/shipkit-org) (2), [Tim van der Lippe](https://github.com/TimvdLippe) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.6.0-green.svg)](https://bintray.com/mockito/maven/mockito/3.6.0) + - Retry the release [(#2078)](https://github.com/mockito/mockito/pull/2078) + - Retry 3.6.0 release [(#2077)](https://github.com/mockito/mockito/pull/2077) + +#### 3.5.15 + - 2020-10-19 - [4 commits](https://github.com/mockito/mockito/compare/v3.5.14...v3.5.15) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.15-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.15) + - Mock resolver plugin [(#2042)](https://github.com/mockito/mockito/pull/2042) + +#### 3.5.14 + - 2020-10-17 - [2 commits](https://github.com/mockito/mockito/compare/v3.5.13...v3.5.14) by [Marcono1234](https://github.com/Marcono1234) (1), [shestee](https://github.com/shestee) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.14-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.5.14) + - Fixes #2061: ArgumentMatcher error messages use lambda class names [(#2071)](https://github.com/mockito/mockito/pull/2071) + - Fixed typo in osgi.gradle [(#2070)](https://github.com/mockito/mockito/pull/2070) + - Lambda used as ArgumentMatcher causes decamelized lambda name to appear in error message [(#2061)](https://github.com/mockito/mockito/issues/2061) + +#### 3.5.13 + - 2020-09-24 - [1 commit](https://github.com/mockito/mockito/compare/v3.5.12...v3.5.13) by [Sinan Kozak](https://github.com/kozaxinan) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.13-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.13) + - Use single version for strictly in mockito-android [(#2053)](https://github.com/mockito/mockito/pull/2053) + +#### 3.5.12 + - 2020-09-18 - [1 commit](https://github.com/mockito/mockito/compare/v3.5.11...v3.5.12) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.12-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.5.12) + - Update Byte Buddy. [(#2050)](https://github.com/mockito/mockito/pull/2050) + +#### 3.5.11 + - 2020-09-17 - [2 commits](https://github.com/mockito/mockito/compare/v3.5.10...v3.5.11) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.11-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.11) + - Do not exclude synthetic constructors from instrumentation. Fixes #2040. [(#2046)](https://github.com/mockito/mockito/pull/2046) + - Mockito.spy(Activity).getBaseContext() returns null on Robolectric 4.4 and Java8 [(#2040)](https://github.com/mockito/mockito/issues/2040) + +#### 3.5.10 + - 2020-09-03 - [2 commits](https://github.com/mockito/mockito/compare/v3.5.9...v3.5.10) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.10-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.10) + - Escape mock during method dispatch on mock to avoid premature garbage collection. [(#2034)](https://github.com/mockito/mockito/pull/2034) + - Exception "The mock object was garbage collected." [(#1802)](https://github.com/mockito/mockito/issues/1802) + +#### 3.5.9 + - 2020-09-01 - [1 commit](https://github.com/mockito/mockito/compare/v3.5.8...v3.5.9) by [Sinan Kozak](https://github.com/kozaxinan) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.9-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.9) + - Fixes #2007 : Downgrade objenesis version for mockito-android [(#2024)](https://github.com/mockito/mockito/pull/2024) + - Android instrumentation test packaging fails for mockito-android 3.5.0 with minSdk < 26 [(#2007)](https://github.com/mockito/mockito/issues/2007) + +#### 3.5.8 + - 2020-08-27 - [1 commit](https://github.com/mockito/mockito/compare/v3.5.7...v3.5.8) by [ahmadmoawad](https://github.com/ahmadmoawad) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.8-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.5.8) + - Fix typo in CONTRIBUTING.md and SpyOnInjectedFieldsHandler [(#1994)](https://github.com/mockito/mockito/pull/1994) + +#### 3.5.7 + - 2020-08-25 - [2 commits](https://github.com/mockito/mockito/compare/v3.5.6...v3.5.7) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.7-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.7) + - Initializes classes prior to instrumentation to avoid uncontrolled code execution. [(#2023)](https://github.com/mockito/mockito/pull/2023) + - Stackoverflow error when upgrading to v3.5.2 [(#2011)](https://github.com/mockito/mockito/issues/2011) + +#### 3.5.6 + - 2020-08-24 - [5 commits](https://github.com/mockito/mockito/compare/v3.5.5...v3.5.6) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.6-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.6) + - Only apply argument on illegal module access for inline tests if Java version is at least 9. [(#2022)](https://github.com/mockito/mockito/pull/2022) + - Constructor dispatch [(#2021)](https://github.com/mockito/mockito/pull/2021) + +#### 3.5.5 + - 2020-08-22 - [3 commits](https://github.com/mockito/mockito/compare/v3.5.4...v3.5.5) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.5-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.5) + - Constructor dispatch [(#2020)](https://github.com/mockito/mockito/pull/2020) + +#### 3.5.4 + - 2020-08-21 - [2 commits](https://github.com/mockito/mockito/compare/v3.5.3...v3.5.4) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.4-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.4) + - Only enable mocking of types right before instantiation to avoid circular interception of constructor creation. [(#2017)](https://github.com/mockito/mockito/pull/2017) + +#### 3.5.3 + - 2020-08-20 - [3 commits](https://github.com/mockito/mockito/compare/v3.5.2...v3.5.3) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.3-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.3) + - [ci maven-central-release] Constructor dispatch [(#2013)](https://github.com/mockito/mockito/pull/2013) + - Constructor not called when using mockito-inline (3.5.x) [(#2012)](https://github.com/mockito/mockito/issues/2012) + +#### 3.5.2 + - 2020-08-18 - [1 commit](https://github.com/mockito/mockito/compare/v3.5.1...v3.5.2) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.2-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.2) + - No pull requests referenced in commit messages. + +#### 3.5.1 + - 2020-08-18 - [3 commits](https://github.com/mockito/mockito/compare/v3.5.0...v3.5.1) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.1-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.5.1) + - Introduce animal sniffer [(#2006)](https://github.com/mockito/mockito/pull/2006) + +#### 3.5.0 + - 2020-08-15 - [9 commits](https://github.com/mockito/mockito/compare/v3.4.8...v3.5.0) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.5.0-green.svg)](https://bintray.com/mockito/maven/mockito/3.5.0) + - Pre release 3.5.0 [(#2004)](https://github.com/mockito/mockito/pull/2004) + +#### 3.4.8 + - 2020-08-09 - [1 commit](https://github.com/mockito/mockito/compare/v3.4.7...v3.4.8) by [Erhard Pointl](https://github.com/epeee) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.8-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.4.8) + - Update objenesis to 3.1 [(#1998)](https://github.com/mockito/mockito/pull/1998) + +#### 3.4.7 + - 2020-08-05 - [1 commit](https://github.com/mockito/mockito/compare/v3.4.6...v3.4.7) by [Per Lundberg](https://github.com/perlun) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.7-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.4.7) + - Mockito.verify(): fix typo in Javadoc [(#1991)](https://github.com/mockito/mockito/pull/1991) + +#### 3.4.6 + - 2020-07-29 - [3 commits](https://github.com/mockito/mockito/compare/v3.4.5...v3.4.6) by [Rafael Winterhalter](https://github.com/raphw) (2), [Valery Yatsynovich](https://github.com/valfirst) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.6-green.svg)](https://bintray.com/mockito/maven/mockito/3.4.6) + - [Bugfixes] Do not pass static mocks to regular listener callback. [(#1989)](https://github.com/mockito/mockito/pull/1989) + - MockitoJUnitRunner causes NPE when using @Mock on MockedStatic fields [(#1988)](https://github.com/mockito/mockito/issues/1988) + - Fixes #1985 : Update README to refer the latest documentation [(#1986)](https://github.com/mockito/mockito/pull/1986) + - README should refer the latest available documentation [(#1985)](https://github.com/mockito/mockito/issues/1985) + +#### 3.4.5 + - 2020-07-20 - [2 commits](https://github.com/mockito/mockito/compare/v3.4.4...v3.4.5) by [Erhard Pointl](https://github.com/epeee) (1), [Johnny Lim](https://github.com/izeye) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.5-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.4.5) + - Fix typo [(#1984)](https://github.com/mockito/mockito/pull/1984) + - Update assertj to 3.16.1 [(#1982)](https://github.com/mockito/mockito/pull/1982) + +#### 3.4.4 + - 2020-07-18 - [2 commits](https://github.com/mockito/mockito/compare/v3.4.3...v3.4.4) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.4-green.svg)](https://bintray.com/mockito/maven/mockito/3.4.4) + - Fixes #1855 and #939: improve error message when the inline mock maker cannot be used. [(#1974)](https://github.com/mockito/mockito/pull/1974) + - javax.tools.ToolProvider could not be found in InlineByteBuddyMockMaker [(#1855)](https://github.com/mockito/mockito/issues/1855) + +#### 3.4.3 + - 2020-07-17 - [1 commit](https://github.com/mockito/mockito/compare/v3.4.2...v3.4.3) by [Robert Chmielowiec](https://github.com/chmielowiec) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.3-green.svg)](https://bintray.com/mockito/maven/mockito/3.4.3) + - Fix Javadoc invalid syntax [(#1978)](https://github.com/mockito/mockito/pull/1978) + - Broken documentation [(#1977)](https://github.com/mockito/mockito/issues/1977) + +#### 3.4.2 + - 2020-07-16 - [2 commits](https://github.com/mockito/mockito/compare/v3.4.1...v3.4.2) by [Rafael Winterhalter](https://github.com/raphw) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.2-green.svg)](https://bintray.com/mockito/maven/mockito/3.4.2) + - Fixes #1967: Correctly handle mocks with limited life-cycle in listeners. [(#1968)](https://github.com/mockito/mockito/pull/1968) + - Static method mocks incompatible with MockitoExtension (NotAMockException) [(#1967)](https://github.com/mockito/mockito/issues/1967) + +#### 3.4.1 + - 2020-07-15 - [1 commit](https://github.com/mockito/mockito/compare/v3.4.0...v3.4.1) by [mickroll](https://github.com/mickroll) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.1-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.4.1) + - update dependency to byte buddy version 1.10.13 [(#1973)](https://github.com/mockito/mockito/pull/1973) + - Update dependency to byte buddy version 1.10.13 [(#1972)](https://github.com/mockito/mockito/issues/1972) + +#### 3.4.0 + - 2020-07-10 - [19 commits](https://github.com/mockito/mockito/compare/v3.3.12...v3.4.0) by 9 authors - published to [![Bintray](https://img.shields.io/badge/Bintray-3.4.0-green.svg)](https://bintray.com/mockito/maven/mockito/3.4.0) + - Commits: [Tim van der Lippe](https://github.com/TimvdLippe) (5), [Erhard Pointl](https://github.com/epeee) (4), [Rafael Winterhalter](https://github.com/raphw) (3), [Eitan Adler](https://github.com/grimreaper) (2), adrianriley (1), akluball (1), [Artem Prigoda](https://github.com/arteam) (1), [Jamie Tanna](https://github.com/jamietanna) (1), [Naoki Takezoe](https://github.com/takezoe) (1) + - [Android support] Enable mocking static methods in Mockito [(#1013)](https://github.com/mockito/mockito/issues/1013) + - Document using `@Mock` with method parameters [(#1961)](https://github.com/mockito/mockito/pull/1961) + - Documentation: `@Mock` on method parameters [(#1960)](https://github.com/mockito/mockito/issues/1960) + - Update errorprone gradle plugin to v1.2.1 [(#1958)](https://github.com/mockito/mockito/pull/1958) + - Update spotless Travis job name to be more descriptive [(#1957)](https://github.com/mockito/mockito/pull/1957) + - Fix a confusing typo in subclassing error message [(#1953)](https://github.com/mockito/mockito/pull/1953) + - Update bnd gradle plugin to v5.1.1 [(#1952)](https://github.com/mockito/mockito/pull/1952) + - Use errorprone 2.4.0 [(#1951)](https://github.com/mockito/mockito/pull/1951) + - Use jacoco v0.8.5 [(#1950)](https://github.com/mockito/mockito/pull/1950) + - Fixes #1712 : prepend description to AssertionError thrown in verification [(#1949)](https://github.com/mockito/mockito/pull/1949) + - Update gradle 6 [(#1948)](https://github.com/mockito/mockito/pull/1948) + - Move spotless check to separate build task [(#1946)](https://github.com/mockito/mockito/pull/1946) + - [Travis] Replace JDK 9/10 with 14 [(#1945)](https://github.com/mockito/mockito/pull/1945) + - Fixes #1898 : Return mock name from toString method for deep stub mocks [(#1942)](https://github.com/mockito/mockito/pull/1942) + - [checkstyle] switch to new DTD [(#1940)](https://github.com/mockito/mockito/pull/1940) + - Use google-java-format in spotless [(#1934)](https://github.com/mockito/mockito/pull/1934) + - Update report message to use any() instead of anyObject() [(#1931)](https://github.com/mockito/mockito/pull/1931) + - [build] bump gradle to latest 5.x release [(#1923)](https://github.com/mockito/mockito/pull/1923) + - [build] update gradle-errorprone-plugin to 1.1.0 [(#1908)](https://github.com/mockito/mockito/pull/1908) + - RETURNS_DEEP_STUBS override a mock's toString to `null` [(#1898)](https://github.com/mockito/mockito/issues/1898) + - "description" not printing when verify args don't match [(#1712)](https://github.com/mockito/mockito/issues/1712) + +#### 3.3.12 + - 2020-05-25 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.11...v3.3.12) by [Vinicius Scheidegger](https://github.com/vinischeidegger) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.12-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.12) + - Update javadoc - remove deprecated class [(#1938)](https://github.com/mockito/mockito/pull/1938) + +#### 3.3.11 + - 2020-05-14 - [5 commits](https://github.com/mockito/mockito/compare/v3.3.10...v3.3.11) by [Andrei Silviu Dragnea](https://github.com/andreisilviudragnea) (2), [Szczepan Faber](https://github.com/mockitoguy) (2), [Eitan Adler](https://github.com/grimreaper) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.11-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.11) + - JUnit 5 strict stubs check should not suppress the regular test failure [(#1928)](https://github.com/mockito/mockito/pull/1928) + - Fix import order [(#1927)](https://github.com/mockito/mockito/pull/1927) + - [build] add ben-manes dependency upgrade finder [(#1922)](https://github.com/mockito/mockito/pull/1922) + +#### 3.3.10 + - 2020-04-30 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.9...v3.3.10) by [netbeansuser2019](https://github.com/netbeansuser2019) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.10-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.10) + - Update dependencies.gradle [(#1920)](https://github.com/mockito/mockito/pull/1920) + +#### 3.3.9 + - 2020-04-20 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.8...v3.3.9) by [dean-burdaky](https://github.com/dean-burdaky) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.9-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.9) + - Fix Pattern matcher not matching to subregion [(#1914)](https://github.com/mockito/mockito/pull/1914) + - ArgumentMatchers.matches not working [(#1905)](https://github.com/mockito/mockito/issues/1905) + +#### 3.3.8 + - 2020-04-15 - [2 commits](https://github.com/mockito/mockito/compare/v3.3.7...v3.3.8) by [Eitan Adler](https://github.com/grimreaper) (1), [NanjanChung](https://github.com/NanjanChung) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.8-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.8) + - Fixes #1910: update description of ArgumentMatcher javadoc [(#1911)](https://github.com/mockito/mockito/pull/1911) + - Documentation of ArgumentMatchers any() is confusing [(#1910)](https://github.com/mockito/mockito/issues/1910) + - [tests] use ArgumentMatchers over Matchers [(#1907)](https://github.com/mockito/mockito/pull/1907) + +#### 3.3.7 + - 2020-04-12 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.6...v3.3.7) by [Eitan Adler](https://github.com/grimreaper) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.7-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.7) + - [documentation] change deprecated warnings from 3.x -> 4.x [(#1906)](https://github.com/mockito/mockito/pull/1906) + +#### 3.3.6 + - 2020-03-25 - [3 commits](https://github.com/mockito/mockito/compare/v3.3.5...v3.3.6) by [Marcin Mikołajczyk](https://github.com/mikolajczykmarcin) (2), [Alex Wilson](https://github.com/mrwilson) (1) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.6-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.6) + - Feature/returns empty java8 time [(#1896)](https://github.com/mockito/mockito/pull/1896) + - Fixes #1894 checkstyle error on windows [(#1895)](https://github.com/mockito/mockito/pull/1895) + - Checkstyle error on windows [(#1894)](https://github.com/mockito/mockito/issues/1894) + - Make JARs build reproducibly [(#1892)](https://github.com/mockito/mockito/pull/1892) + - Build is not reproducible [(#1891)](https://github.com/mockito/mockito/issues/1891) + - Add java.time types to ReturnsEmptyValues [(#1885)](https://github.com/mockito/mockito/issues/1885) + +#### 3.3.5 + - 2020-03-23 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.4...v3.3.5) by [Shyam Sundar J](https://github.com/severussundar) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.5-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.5) + - Fixes #id : 1888 [(#1893)](https://github.com/mockito/mockito/pull/1893) + - Documentation typo [(#1888)](https://github.com/mockito/mockito/issues/1888) + +#### 3.3.4 + - 2020-03-21 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.3...v3.3.4) by [dean-burdaky](https://github.com/dean-burdaky) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.4-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.4) + - Fix mocks throwing same instance with throwable class [(#1890)](https://github.com/mockito/mockito/pull/1890) + - thenThrow(Class) no longer creates new instances [(#1875)](https://github.com/mockito/mockito/issues/1875) + +#### 3.3.3 + - 2020-03-13 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.2...v3.3.3) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.3-green.svg)](https://bintray.com/mockito/maven/mockito/3.3.3) + - No pull requests referenced in commit messages. + +#### 3.3.2 + - 2020-02-28 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.1...v3.3.2) by [Jean-Michel Leclercq](https://github.com/LeJeanbono) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.2-green.svg)](https://bintray.com/mockito/maven/mockito-development/3.3.2) + - Fix UnnecessaryStubbingException javadoc [(#1881)](https://github.com/mockito/mockito/pull/1881) + +#### 3.3.1 + - 2020-02-26 - [1 commit](https://github.com/mockito/mockito/compare/v3.3.0...v3.3.1) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.1-green.svg)](https://bintray.com/mockito/maven/mockito/3.3.1) + - Revert "Fixed undetected unused stubbing when matching previous stubbed call" [(#1878)](https://github.com/mockito/mockito/pull/1878) #### 3.3.0 - 2020-02-21 - [1 commit](https://github.com/mockito/mockito/compare/v3.2.11...v3.3.0) by [Tim van der Lippe](https://github.com/TimvdLippe) - published to [![Bintray](https://img.shields.io/badge/Bintray-3.3.0-green.svg)](https://bintray.com/mockito/maven/mockito/3.3.0) @@ -1728,7 +1936,7 @@ Last version published to Maven Central after the team adopted [Continuous Deliv * Commits: 5 * 2: Brice Dutheil * 2: Christian Schwarz - * 1: Felix Dekker + * 1: F.W. Dekker * Improvements: 4 * Replaced ObjectBox with AtomicReference [(#777)](https://github.com/mockito/mockito/pull/777) * InvocationMatcher internal improvements [(#776)](https://github.com/mockito/mockito/pull/776) diff --git a/gradle.properties b/gradle.properties index 5970e287bb..377b887db4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,24 @@ org.gradle.daemon=true org.gradle.parallel=true org.gradle.caching=true +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 \ + -XX:+IgnoreUnrecognizedVMOptions \ + --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ + --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ + --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ + --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ + --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ + --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official + +# Version of JDK to use for running tests. +# Possible values: +# - auto -> use Java running Gradle, best for local dev. +# - A Java major version number, like 11 or 17. +mockito.test.java=auto diff --git a/gradle/coverage.gradle b/gradle/coverage.gradle new file mode 100644 index 0000000000..5f5012e5c9 --- /dev/null +++ b/gradle/coverage.gradle @@ -0,0 +1,65 @@ +rootProject.subprojects { Project project -> + plugins.withId("java") { + project.apply plugin: "jacoco" + project.jacoco { + toolVersion = '0.8.11' + } + } +} + +def mockitoCoverage = tasks.register("mockitoCoverage", JacocoReport) { mockitoCoverage -> + group = LifecycleBasePlugin.VERIFICATION_GROUP + rootProject.subprojects { Project currentProject -> + plugins.withId("jacoco") { + plugins.withId("java") { + // JacocoReport.sourceSets() appends both sourceDirectories and classDirectories. + mockitoCoverage.sourceSets currentProject.sourceSets.main + mockitoCoverage.executionData(currentProject.tasks.test) + } + plugins.withId("com.android.base") { + // The :androidTest project only contains test infrastructure, so there's no need to grab sources/classes. + + def androidTest = currentProject.tasks.connectedDebugAndroidTest + def instrumentationCoverage = currentProject + .layout.buildDirectory.dir("outputs/code_coverage/debugAndroidTest/connected") + .map { it.asFileTree.matching { include "*/coverage.ec" } } + mockitoCoverage.executionData(currentProject.files(instrumentationCoverage)) + mockitoCoverage.mustRunAfter(androidTest) + + def unitTest = currentProject.tasks.testDebugUnitTest + def coverageFiles = currentProject + .layout.buildDirectory.dir("outputs/unit_test_code_coverage/debugUnitTest") + .map { it.asFileTree.matching { include "testDebugUnitTest.exec" } } + mockitoCoverage.executionData(currentProject.files(coverageFiles).builtBy(unitTest)) + } + } + } + + gradle.taskGraph.whenReady { // Theoretically Gradle.projectsEvaluated, but not possible here. + // Run this after all projects' sourceSets have been added (which is delayed to when the jacoco plugin is applied). + classDirectories.setFrom( + classDirectories.files.collect { + fileTree( + dir: it, + exclude: ["**/internal/util/concurrent/**"] + ) + } + ) + } + + reports { + xml.required = true + html.required = true + html.outputLocation = rootProject.layout.buildDirectory.dir("jacocoHtml") + } + + doLast { + def reportFile = new File(reports.html.outputLocation.get().asFile, "index.html") + logger.lifecycle "Jacoco HTML created: file://${reportFile.toURI().path}" + } +} + +tasks.register("coverageReport") { + group = LifecycleBasePlugin.VERIFICATION_GROUP + dependsOn(mockitoCoverage) +} diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle deleted file mode 100644 index e052dad88e..0000000000 --- a/gradle/dependencies.gradle +++ /dev/null @@ -1,48 +0,0 @@ -ext { - libraries = [:] -} - -def versions = [:] - -versions.bytebuddy = '1.10.5' -versions.junitJupiter = '5.4.2' -versions.errorprone = '2.3.2' - -libraries.junit4 = 'junit:junit:4.12' -libraries.junitJupiterApi = "org.junit.jupiter:junit-jupiter-api:${versions.junitJupiter}" -libraries.junitPlatformLauncher = 'org.junit.platform:junit-platform-launcher:1.1.0' -libraries.junitJupiterEngine = "org.junit.jupiter:junit-jupiter-engine:${versions.junitJupiter}" -libraries.assertj = 'org.assertj:assertj-core:3.15.0' -libraries.hamcrest = 'org.hamcrest:hamcrest-core:1.3' -libraries.opentest4j = 'org.opentest4j:opentest4j:1.1.1' - -libraries.bytebuddy = "net.bytebuddy:byte-buddy:${versions.bytebuddy}" -libraries.bytebuddyagent = "net.bytebuddy:byte-buddy-agent:${versions.bytebuddy}" -libraries.bytebuddyandroid = "net.bytebuddy:byte-buddy-android:${versions.bytebuddy}" - -libraries.errorprone = "com.google.errorprone:error_prone_core:${versions.errorprone}" -libraries.errorproneTestApi = "com.google.errorprone:error_prone_test_helpers:${versions.errorprone}" - -libraries.autoservice = "com.google.auto.service:auto-service:1.0-rc5" - -// objenesis 3.x with full Java 11 support requires Java 8, bump version when Java 7 support is dropped -libraries.objenesis = 'org.objenesis:objenesis:2.6' - -libraries.asm = 'org.ow2.asm:asm:7.0' - -libraries.osgi = 'org.osgi:osgi.core:7.0.0' -libraries.equinox = 'org.eclipse.platform:org.eclipse.osgi:3.15.0' -libraries.bndGradle = 'biz.aQute.bnd:biz.aQute.bnd.gradle:4.3.1' - -def kotlinVersion = '1.2.10' -def kotlinVersion_1_3 = '1.3.0-rc-57' -libraries.kotlin = [ - version: kotlinVersion, - version_1_3: kotlinVersion_1_3, - - stdlib: "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}", - coroutines: 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.3', - - stdlib_1_3: "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion_1_3", - releaseCoroutines: "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.26.1-eap13" -] diff --git a/gradle/errorprone.gradle b/gradle/errorprone.gradle deleted file mode 100644 index 43c8633fcd..0000000000 --- a/gradle/errorprone.gradle +++ /dev/null @@ -1,16 +0,0 @@ - -apply plugin: "net.ltgt.errorprone" - -if (JavaVersion.current() == JavaVersion.VERSION_1_8) { - dependencies { - errorproneJavac("com.google.errorprone:javac:9+181-r4173-1") - } -} - -dependencies { - errorprone libraries.errorprone -} - -tasks.named("compileTestJava").configure { - options.errorprone.errorproneArgs << "-Xep:MockitoCast:OFF" -} diff --git a/gradle/java-library.gradle b/gradle/java-library.gradle deleted file mode 100644 index be214c6c24..0000000000 --- a/gradle/java-library.gradle +++ /dev/null @@ -1,38 +0,0 @@ -apply plugin: "java" - -group = 'org.mockito' - -if (!archivesBaseName.startsWith("mockito-")) { - archivesBaseName = "mockito-" + project.name -} - -generatePomFileForJavaLibraryPublication.doLast { - //validates the the pom has correct artifact id to avoid issues like #1444 - def pom = new XmlSlurper().parse(destination) - assert pom.artifactId == archivesBaseName - assert pom.name == archivesBaseName -} - -bintrayUpload.enabled = true - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -test { - include "**/*Test.class" - - testLogging { - exceptionFormat 'full' - showCauses true - } -} - -apply from: "$rootDir/gradle/retry-test.gradle" - -tasks.withType(Checkstyle) { - reports { - xml.enabled false - html.enabled true - html.stylesheet resources.text.fromFile("$rootDir/config/checkstyle/checkstyle.xsl") - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000000..2e02e29680 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,60 @@ +[versions] +bytebuddy = "1.15.11" +errorprone = "2.23.0" +junit4 = "4.13.2" +junit-jupiter = "5.11.4" +junit-platform = "1.11.4" +kotlin = "2.0.21" + +gradleplugin-test-logger = "4.0.0" +gradleplugin-animal-sniffer = "1.7.2" +gradleplugin-aQute-bnd = "7.1.0" +gradleplugin-errorprone = "4.1.0" +gradleplugin-spotless = "7.0.2" + +gradleplugin-android = "7.4.2" + +[libraries] +android-junit = { module = "androidx.test.ext:junit", version = "1.2.1" } +android-runner = { module = "androidx.test:runner", version = "1.6.2" } +assertj = { module = "org.assertj:assertj-core", version = "3.27.3" } +autoservice = { module = "com.google.auto.service:auto-service", version = "1.1.1" } +bnd-gradle = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "gradleplugin-aQute-bnd" } +bytebuddy = { module = "net.bytebuddy:byte-buddy", version.ref = "bytebuddy" } +bytebuddy-agent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "bytebuddy" } +bytebuddy-android = { module = "net.bytebuddy:byte-buddy-android", version.ref = "bytebuddy" } +equinox = { module = "org.eclipse.platform:org.eclipse.osgi", version = "3.22.0" } +errorprone = { module = "com.google.errorprone:error_prone_core", version.ref = "errorprone" } +errorprone-test-api = { module = "com.google.errorprone:error_prone_test_helpers", version.ref = "errorprone" } +groovy = { module = "org.codehaus.groovy:groovy", version = "3.0.23" } +hamcrest = { module = "org.hamcrest:hamcrest-core", version = "3.0" } +junit4 = { module = "junit:junit", version.ref = "junit4" } +junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter" } +junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" } +junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit-jupiter" } +junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit-platform" } +junit-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit-jupiter" } +kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } +kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.6.3-native-mt" } +objenesis = { module = "org.objenesis:objenesis", version = "3.3" } +opentest4j = { module = "org.opentest4j:opentest4j", version = "1.3.0" } +osgi = { module = "org.osgi:osgi.core", version = "8.0.0" } + +# For buildSrc logic +gradleplugin-testLogger = { module = "com.adarshr:gradle-test-logger-plugin", version.ref = "gradleplugin-test-logger" } +gradleplugin-animalSniffer = { module = "ru.vyarus:gradle-animalsniffer-plugin", version.ref = "gradleplugin-animal-sniffer" } +gradleplugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "gradleplugin-aQute-bnd" } +gradleplugin-errorprone = { module = "net.ltgt.gradle:gradle-errorprone-plugin", version.ref = "gradleplugin-errorprone" } +gradleplugin-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "gradleplugin-spotless" } +gradleplugin-spotless-googleJavaFormat = { module = "com.google.googlejavaformat:google-java-format", version = "1.25.2" } +gradleplugin-license = { module = "com.github.hierynomus.license:com.github.hierynomus.license.gradle.plugin", version = "0.16.1" } +gradleplugin-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version = "2.0.0" } +gradleplugin-shipkit-changelog = { module = "org.shipkit:shipkit-changelog", version = "2.0.1" } +gradleplugin-shipkit-autoVersion = { module = "org.shipkit:shipkit-auto-version", version = "2.1.0" } + +# animal sniffer compatibility signatures +animalSniffer-android-apiLevel26 = { module = "net.sf.androidscents.signature:android-api-level-26", version = "8.0.0_r2" } +animalSniffer-java = { module = "org.codehaus.mojo.signature:java18", version = "1.0" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "gradleplugin-android" } diff --git a/gradle/license.gradle b/gradle/license.gradle deleted file mode 100644 index f6eb52d899..0000000000 --- a/gradle/license.gradle +++ /dev/null @@ -1,16 +0,0 @@ -def licenseHeaderFile = rootProject.file('doc/licenses/HEADER.txt') - -allprojects { - apply plugin: 'com.github.hierynomus.license' - license { - header = licenseHeaderFile - strictCheck = true - ignoreFailures = true - skipExistingHeaders = true - mapping { - java = 'SLASHSTAR_STYLE' - groovy = 'SLASHSTAR_STYLE' - } - ext.year = Calendar.getInstance().get(Calendar.YEAR) - } -} diff --git a/gradle/mockito-core/inline-mock.gradle b/gradle/mockito-core/inline-mock.gradle deleted file mode 100644 index ae39ffeec1..0000000000 --- a/gradle/mockito-core/inline-mock.gradle +++ /dev/null @@ -1,15 +0,0 @@ -task copyMockMethodDispatcher(type: Copy) { - dependsOn compileJava - from "${sourceSets.main.java.outputDir}/org/mockito/internal/creation/bytebuddy/inject" - into "${sourceSets.main.java.outputDir}/org/mockito/internal/creation/bytebuddy/inject" - include "MockMethodDispatcher.class" - rename { String fileName -> - fileName.replace('.class', '.raw') - } -} -classes.dependsOn(copyMockMethodDispatcher) - -jar { - exclude("org/mockito/internal/creation/bytebuddy/inject/package-info.class") - exclude("org/mockito/internal/creation/bytebuddy/inject/MockMethodDispatcher.class") -} diff --git a/gradle/mockito-core/javadoc.gradle b/gradle/mockito-core/javadoc.gradle deleted file mode 100644 index 0ed36bb960..0000000000 --- a/gradle/mockito-core/javadoc.gradle +++ /dev/null @@ -1,74 +0,0 @@ -//It seems the gradle javadoc task works file by file and as such disable some features of javadoc tool -//such as link to packages, https://groups.google.com/d/msg/gradle-dev/R83dy_6PHMc/bgw0cUTMFAAJ -javadoc { - description "Creates javadoc html for Mockito API." - - // For more details on the format - // see https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html - - source = sourceSets.main.allJava - destinationDir = file("$buildDir/javadoc") - title = "Mockito ${project.version} API" - - // The way *gradle* javadoc task works and due to *gradle exclusion* the log output triggers javadoc warning and - // errors on internal classes that are not found, non-exhaustive list : - // - // * import org.mockito.internal.Internal <- error: package org.mockito.internal does not exists - // * import org.mockito.internal.Internal.util <- error: static import only from classes and interfaces - // * class Public extends Internal <- cannot find symbol - // * warning - Tag @linkplain: reference not found: org.mockito.internal.Internal internal stuff - // * warning - Tag @link: reference not found: org.mockito.stubbing - // - // While there's errors the javadoc is still generated without those symbols or links ; - // for this reason the javadoc output is suppressed and can be reactivated with --info option. - exclude 'org/mockito/internal' - logging.captureStandardError LogLevel.INFO - logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message - - options.docTitle = """

Click to see examples. Mockito ${project.version} API.

""" - options.windowTitle = "Mockito ${project.version} API" - options.group("Main package", ["org.mockito"]) - options.memberLevel = JavadocMemberLevel.PROTECTED - options.outputLevel = JavadocOutputLevel.QUIET - options.charSet = 'UTF-8' - options.encoding = 'UTF-8' - options.docEncoding = 'UTF-8' - options.use = true - options.splitIndex = true - options.noDeprecated = false - options.noDeprecatedList = false - options.noIndex = false - options.noNavBar = false - options.noTree = false - options.links = ['https://docs.oracle.com/javase/6/docs/api/', - 'http://junit.org/junit4/javadoc/4.12/', - 'http://hamcrest.org/JavaHamcrest/javadoc/1.3/'] - options.header("""Mockito ${project.version} API""") - options.footer("""Mockito ${project.version} API""") - options.bottom(""" - - - - - - - """.replaceAll(/\r|\n|[ ]{8}/, "")) - options.stylesheetFile rootProject.file("src/javadoc/stylesheet.css") - options.addStringOption('Xdoclint:none', '-quiet') - - def minorVersion = System.getProperty("java.version") =~ /1.8.0_(\d*)/ - - // Since JDK 8 version 121 scripts are not allowed in comments. However, - // earlier version throw an error if an unknown option is passed. - // Therefore only add this option if the JDK is actually correct. - if (minorVersion.size() > 0 && Integer.valueOf(minorVersion[0][1]) >= 121 || JavaVersion.current().isJava9Compatible()) { - options.addBooleanOption('-allow-script-in-comments', true) - } - - doLast { - copy { - from "src/javadoc" - into "$buildDir/javadoc" - } - } -} diff --git a/gradle/mockito-core/osgi.gradle b/gradle/mockito-core/osgi.gradle deleted file mode 100644 index 1e942f6569..0000000000 --- a/gradle/mockito-core/osgi.gradle +++ /dev/null @@ -1,35 +0,0 @@ -apply plugin: 'osgi' - -afterEvaluate { - tasks.matching { it.name == 'jar' }.all { jar -> - jar.manifest { - classpath = project.configurations.runtime - - instruction '-versionpolicy', '[${version;==;${@}},${version;+;${@}})' - - name = 'Mockito Mock Library for Java. Core bundle requires Byte Buddy and Objenesis.' - symbolicName = 'org.mockito.mockito-core' - version = project.version.replace('-', '.') - - instruction 'Export-Package', - '!org.mockito.internal.*', - "org.mockito.*;version=${version}" - - instruction 'Import-Package', - 'net.bytebuddy.*;version="[1.6.0,2.0)"', - 'junit.*;resolution:=optional', - 'org.junit.*;resolution:=optional', - 'org.hamcrest;resolution:=optional', - 'org.objenesis;version="[2.5,3.0)"', - 'org.opentest4j.*;resolution:=optional', - 'org.mockito.*' - - instruction 'Private-Package', - 'org.mockito.*' - - instruction '-removeheaders', 'Private-Package' - - attributes 'Automatic-Module-Name': 'org.mockito' - } - } -} diff --git a/gradle/mockito-core/testing.gradle b/gradle/mockito-core/testing.gradle deleted file mode 100644 index a7c14c1f62..0000000000 --- a/gradle/mockito-core/testing.gradle +++ /dev/null @@ -1,29 +0,0 @@ -def java11 = System.env.SIMULATE_JAVA11 -if (java11 != null) { - test { - logger.info("$it.path - use Java11 simluation: ${java11}") - systemProperty "org.mockito.internal.noUnsafeInjection", java11 - } -} - -task(createTestResources).doLast { - def mockMakerFile = new File("$projectDir/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker") - if (System.env.MOCK_MAKER != null) { - logger.info("Using MockMaker ${System.env.MOCK_MAKER}") - mockMakerFile.parentFile.mkdirs() - mockMakerFile.createNewFile() - mockMakerFile.write(System.env.MOCK_MAKER) - } else { - logger.info("Using default MockMaker") - } -} - -task(removeTestResources).doLast { - def mockMakerFile = new File("$projectDir/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker") - if (mockMakerFile.exists()) { - mockMakerFile.delete() - } -} - -compileTestJava.dependsOn createTestResources -compileTestJava.finalizedBy removeTestResources diff --git a/gradle/retry-test.gradle b/gradle/retry-test.gradle deleted file mode 100644 index 23ae107237..0000000000 --- a/gradle/retry-test.gradle +++ /dev/null @@ -1,68 +0,0 @@ -/** -Plugin that retries failed tests. -Mockito has concurrent API and those tests and inherently flaky. -We decided to use retries to stabilize (conscious team choice) -Long term, we can evolve retry-test script plugin to a binary plugin or make it more robust - -Plugin adds 'retryTest' task that runs tests that failed during the execution of 'test' task. -*/ -task retryTest(type: Test) { - description = "Retries failed tests (if present)" - enabled = false - doFirst { - logger.lifecycle "[retryTest] retrying ${filter.includePatterns.size()} test(s)." - } - afterSuite { descriptor, result -> - if (!descriptor.parent) { //root - if (result.failedTestCount > 0) { - logger.lifecycle "\n[retryTest] retried ${filter.includePatterns.size()} test(s), $result.failedTestCount still failed." - } else { - logger.lifecycle "\n[retryTest] ${filter.includePatterns.size()} test(s) were retried successfully:\n " + filter.includePatterns.join("\n ") - } - } - } - testClassesDirs = test.testClassesDirs - classpath = test.classpath - scanForTestClasses = test.scanForTestClasses - outputs.upToDateWhen { false } //we want to always run flaky tests because they are flaky - - include "**/*Test.class" - - testLogging { - exceptionFormat 'full' - showCauses true - } -} - -test { - finalizedBy retryTest - ext.failedTests = [] - afterTest { descriptor, result -> - if (!descriptor.composite /* e.g. is not a parent */ && result.failedTestCount > 0 ) { - //adding fully qualified test name, dropping "()" from the method name - failedTests.add(descriptor.className + "." + descriptor.name.replaceAll("\\(\\)", "")) - } - } - afterSuite { descriptor, result -> - if (!descriptor.parent) { //root - def failuresReport = new File(buildDir, name + "-failures.txt") - def deletion = !failuresReport.exists() || failuresReport.delete() - if (!deletion) { - throw new GradleException("Problems deleting failures file: $reportPath. Please delete manually and retry.") - } - def reportPath = rootProject.relativePath(failuresReport) - if (!failedTests.empty) { - failuresReport << failedTests.join("\n") - logger.lifecycle "\n[retryTest] wrote ${failedTests.size()} failed tests to: $reportPath" - logger.info "[retryTest] all failed tests:\n " + failedTests.join("\n ") - retryTest.enabled = true - retryTest.filter.includePatterns = failedTests.toArray(new String[failedTests.size()]) - ignoreFailures = true - } else { - logger.info "\n[retryTest] There are no failed tests, '$reportPath' file was deleted (if existed)." - } - } - } -} - - diff --git a/gradle/root/coverage.gradle b/gradle/root/coverage.gradle deleted file mode 100644 index 03ec3883e6..0000000000 --- a/gradle/root/coverage.gradle +++ /dev/null @@ -1,53 +0,0 @@ -if (!project.hasProperty("jacoco")) { - //JaCoCo plugin prevents using Build Cache. We will enable jacoco configuration only when specific property is supplied - //TODO remove this workaround when we migrate to Gradle 5.0 (https://github.com/gradle/gradle/issues/5269) - logger.info "JaCoCo code coverage will not be configured because 'jacoco' project property is not present." - return //don't evaluate this Gradle file any further -} else { - logger.lifecycle "Configuring JaCoCo code coverage because 'jacoco' project property is present." -} - -//TODO: Standard JaCoCo coverage doesn't work in Android module -task mockitoCoverage(type: JacocoReport) { - - allprojects { currentProject -> - plugins.withId("java") { - mockitoCoverage.sourceSets currentProject.sourceSets.main - - apply plugin: "jacoco" - - jacoco { - toolVersion = '0.8.2' - - if (currentProject != rootProject) { //already automatically enhanced in mockito main project as "java" plugin was applied before - applyTo test - } - test.jacoco.destinationFile = file("${currentProject.buildDir}/jacoco/test.exec") - } - - mockitoCoverage.executionData(files(test.jacoco.destinationFile).builtBy(test)) - } - } - - reports { - xml.enabled true - html.enabled true - html.destination file("${buildDir}/jacocoHtml") - } - - doFirst { - classDirectories.from = classDirectories.files.collect { - fileTree( - dir: it, - exclude: ['**/org/mockito/internal/util/concurrent/**'] - ) - } - executionData.from = executionData.files.findAll { it.exists() } - } - - doLast { - logger.lifecycle "Jacoco HTML created: file://${new File(reports.html.destination, "index.html").toURI().path}" - } -} - -task coverageReport(dependsOn: ["mockitoCoverage"]) {} diff --git a/gradle/root/gradle-fix.gradle b/gradle/root/gradle-fix.gradle deleted file mode 100644 index c37eab2ee2..0000000000 --- a/gradle/root/gradle-fix.gradle +++ /dev/null @@ -1,13 +0,0 @@ - -// GradleWorkerMain ignores options available in the environment, so we have to pass them there - -allprojects { - tasks.withType(JavaForkOptions) { - // should improve memory on a 64bit JVM - jvmArgs "-XX:+UseCompressedOops" - - // should avoid GradleWorkerMain to steal focus - jvmArgs "-Djava.awt.headless=true" - jvmArgs "-Dapple.awt.UIElement=true" - } -} diff --git a/gradle/root/ide.gradle b/gradle/root/ide.gradle deleted file mode 100644 index bfc7ed77d8..0000000000 --- a/gradle/root/ide.gradle +++ /dev/null @@ -1,11 +0,0 @@ -assert rootProject == project - -allprojects { - apply plugin: 'eclipse' - apply plugin: 'idea' -} - -idea.project { - vcs = 'Git' -} - diff --git a/gradle/shipkit.gradle b/gradle/shipkit.gradle deleted file mode 100644 index aa4546cd0e..0000000000 --- a/gradle/shipkit.gradle +++ /dev/null @@ -1,89 +0,0 @@ -shipkit { - gitHub.repository = "mockito/mockito" - gitHub.readOnlyAuthToken = "a0a4c0f41c200f7c653323014d6a72a127764e17" - - releaseNotes.file = "doc/release-notes/official.md" - releaseNotes.labelMapping = [ - '1.* incompatible': 'Incompatible changes with previous major version (v1.x)', - 'java-9': "Java 9 support", - 'java-8': "Java 8 support", - 'new feature': "New features", - 'BDD': 'Behavior-Driven Development support', - 'bug': "Bugfixes", - 'enhancement': "Enhancements", - 'android': "Android support", - 'docs': 'Documentation' - ] - - git.releasableBranchRegex = "release/.+" // 'release/2.x', 'release/3.x', etc. - - def buildNo = System.getenv("TRAVIS_BUILD_NUMBER") - git.commitMessagePostfix = buildNo? "by CI build $buildNo\n\n[ci skip-release]" : "by local build\n\n[ci skip-release]" - - team.developers = ['mockitoguy:Szczepan Faber', 'bric3:Brice Dutheil', 'raphw:Rafael Winterhalter', 'TimvdLippe:Tim van der Lippe'] -} - -/** - * Mockito team does not publish to Maven Central every release as requested by the community. - * We publish to maven central only some versions. All versions are published to Bintray on every change. - * See https://github.com/mockito/mockito/issues/911 - */ -boolean centralRelease = shouldReleaseToCentral(project) - -afterEvaluate { - //using afterEvaluate because 'assertReleaseNeeded' task is added after 'shipkit.gradle' file is evaluated by Gradle - [assertReleaseNeeded, releaseNeeded].each { - it.skipComparePublications = centralRelease - } -} - -allprojects { - plugins.withId("org.shipkit.bintray") { - bintray { - pkg { - repo = 'maven' //https://bintray.com/mockito/maven - - //We need to use some user id here, because the Bintray key is associated with the user - //However, any user id is good, so longer the user has necessary privileges to the repository - user = 'szczepiq' //https://bintray.com/szczepiq - - userOrg = 'mockito' //https://bintray.com/mockito - name = 'mockito' //https://bintray.com/mockito/maven/mockito - licenses = ['MIT'] - labels = ['mocks', 'tdd', 'unit tests'] - publish = true //can be changed to 'false' for testing - - //See our Bintray packages at https://bintray.com/mockito/maven - name = centralRelease? "mockito" : "mockito-development" - - version { - //Notable versions are automatically synced to Maven Central repository (https://oss.sonatype.org/) - mavenCentralSync { - sync = centralRelease - user = System.env.NEXUS_TOKEN_USER - password = System.env.NEXUS_TOKEN_PWD - } - } - } - } - } -} - -/** - * Finds out if we should release to Maven Central. - * To test this logic, run build with '-i' (info logging) and inspect the build output. - */ -static boolean shouldReleaseToCentral(project) { - boolean centralReleaseByCommit = System.getenv("TRAVIS_COMMIT_MESSAGE")?.contains("[ci maven-central-release]") - boolean centralReleaseByProjectProperty = project.hasProperty("maven-central-release") - boolean centralRelease = centralReleaseByCommit || centralReleaseByProjectProperty - def message = """Release was using following settings: - - commit message contains '[ci maven-central-release]': $centralReleaseByCommit - - project property 'maven-central-release' exists: $centralReleaseByProjectProperty - - Maven Central release is enabled: $centralRelease""" - project.logger.info(message) - project.afterEvaluate { - project.tasks.performRelease.doLast { logger.lifecycle(message) } - } - return centralRelease -} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0d4a951687..d64cd49177 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ea13fdfd19..fb602ee2af 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip +distributionSha256Sum=31c55713e40233a8303827ceb42ca48a47267a0ad4bab9177123121e71524c26 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d517..1aa94a4269 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,127 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f9553162f1..93e3f59f13 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,19 +25,23 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/mockito-bom/build.gradle.kts b/mockito-bom/build.gradle.kts new file mode 100644 index 0000000000..8ed867a9cb --- /dev/null +++ b/mockito-bom/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + id("java-platform") + id("mockito.publication-conventions") +} + +description = "Mockito Bill of Materials (BOM)" + +if (!base.archivesName.get().startsWith("mockito-")) { + logger.warn("Project module should be prefixed with `mockito-` : ${project.projectDir})") + base.archivesName = "mockito-" + project.name +} + +val mockitoExtensions: Set = project(":mockito-extensions").subprojects +dependencies { + constraints { + api(project(":mockito-core")) + + mockitoExtensions.forEach { + api(it) + } + } +} diff --git a/mockito-core/build.gradle.kts b/mockito-core/build.gradle.kts new file mode 100644 index 0000000000..0c15d91275 --- /dev/null +++ b/mockito-core/build.gradle.kts @@ -0,0 +1,240 @@ +import com.android.build.gradle.internal.tasks.factory.dependsOn +import org.objectweb.asm.ClassReader +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.ModuleVisitor +import org.objectweb.asm.Opcodes + +plugins { + id("mockito.library-conventions") + id("mockito.java-backward-compatibility-checks-conventions") + id("mockito.javadoc-conventions") + id("java-test-fixtures") +} + +description = "Mockito mock objects library core API and implementation" +base.archivesName = "mockito-core" + +apply { + from(rootProject.file("gradle/coverage.gradle")) +} + +configurations { + // Putting 'provided' dependencies on testCompileOnly and testRuntimeOnly classpath. + testCompileOnly.configure { + extendsFrom(compileOnly.get()) + } + testRuntimeOnly.configure { + extendsFrom(compileOnly.get()) + } +} + +// Disables publishing test fixtures: +// https://docs.gradle.org/current/userguide/java_testing.html#ex-disable-publishing-of-test-fixtures-variants +with(components["java"] as AdhocComponentWithVariants) { + withVariantsFromConfiguration(configurations.testFixturesApiElements.get()) { skip() } + withVariantsFromConfiguration(configurations.testFixturesRuntimeElements.get()) { skip() } +} + +dependencies { + api(libs.bytebuddy) + api(libs.bytebuddy.agent) + + compileOnly(libs.junit4) + compileOnly(libs.hamcrest) + compileOnly(libs.opentest4j) + implementation(libs.objenesis) + + testImplementation(libs.assertj) + testImplementation(libs.junit.jupiter.api) + testImplementation(libs.junit.jupiter.params) + + testFixturesImplementation(libs.assertj) + testFixturesImplementation(libs.objenesis) + testFixturesCompileOnly(libs.junit4) +} + +mockitoJavadoc { + title = "Mockito ${project.version} API" + docTitle = + """

Click to see examples. Mockito ${project.version} API.

""" +} + +val generatedInlineResource: Provider = layout.buildDirectory.dir("generated/resources/inline/java") +sourceSets { + main { + resources { + output.dir(generatedInlineResource) + } + } +} + +tasks { + val copyMockMethodDispatcher by registering(Copy::class) { + dependsOn(compileJava) + + from(sourceSets.main.flatMap { it.java.classesDirectory } + .map { it.file("org/mockito/internal/creation/bytebuddy/inject/MockMethodDispatcher.class") }) + into(generatedInlineResource.map { it.dir("org/mockito/internal/creation/bytebuddy") }) + + rename(".*", "inject-MockMethodDispatcher.raw") + } + + val removeInjectionPackageFromModuleInfo by registering(DefaultTask::class) { + dependsOn(compileJava) + + doLast { + val moduleInfo = sourceSets.main.get().output.classesDirs.first().resolve("module-info.class") + + val reader = ClassReader(moduleInfo.readBytes()) + val writer = ClassWriter(reader, 0) + reader.accept(object : ClassVisitor(Opcodes.ASM9, writer) { + override fun visitModule(name: String?, access: Int, version: String?): ModuleVisitor { + return object : ModuleVisitor( + Opcodes.ASM9, + super.visitModule(name, access, version) + ) { + override fun visitPackage(packaze: String) { + if (packaze != "org/mockito/internal/creation/bytebuddy/inject") { + super.visitPackage(packaze) + } + } + } + } + }, 0) + + moduleInfo.writeBytes(writer.toByteArray()) + } + } + + classes.dependsOn(copyMockMethodDispatcher) + classes.dependsOn(removeInjectionPackageFromModuleInfo) + + + jar { + exclude( + "org/mockito/internal/creation/bytebuddy/inject/package-info.class", + "org/mockito/internal/creation/bytebuddy/inject/MockMethodDispatcher.class", + ) + manifest { + attributes( + "Premain-Class" to "org.mockito.internal.PremainAttach", + "Can-Retransform-Classes" to "true", + ) + } + + bundle { // this: BundleTaskExtension + classpath(project.configurations.compileClasspath) + bnd( + """ + # Bnd instructions for the Mockito core bundle. + + # Set a bundle name slightly different from project description. + Bundle-Name: Mockito Mock Library for Java. Core bundle requires Byte Buddy and Objenesis. + + # Set the Bundle-SymbolicName to "org.mockito.mockito-core". + # Otherwise bnd plugin will use archiveClassifier by default. + Bundle-SymbolicName: org.mockito.mockito-core + + # Version rules for the bundle. + # https://bnd.bndtools.org/macros/version_cleanup.html + Bundle-Version: ${'$'}{version_cleanup;${project.version}} + + # Set bundle license + Bundle-License: MIT + + # Export rules for public and internal packages + # https://bnd.bndtools.org/heads/export_package.html + Export-Package: \ + !org.mockito.internal.creation.bytebuddy.inject,org.mockito.internal.*;status=INTERNAL;mandatory:=status;version=${archiveVersion.get()}, \ + !org.mockito.internal.creation.bytebuddy.inject,org.mockito.*;version=${archiveVersion.get()} + + # General rules for package import + # https://bnd.bndtools.org/heads/import_package.html + # Override the default version policy to allow for a range of versions. + # At this point it's unclear whether `versionpolicy` is deprecated, here's + # some relevant pages on versions + # https://bnd.bndtools.org/chapters/170-versioning.html + # https://bnd.bndtools.org/macros/version.html + # https://bnd.bndtools.org/macros/versionmask.html + # https://bnd.bndtools.org/macros/range.html + -versionpolicy: [${'$'}{version;==;${'$'}{@}},${'$'}{version;+;${'$'}{@}}) + Import-Package: \ + net.bytebuddy.*;version="[1.6.0,2.0)", \ + junit.*;resolution:=optional, \ + org.junit.*;resolution:=optional, \ + org.hamcrest;resolution:=optional, \ + org.objenesis;version="[3.1,4.0)", \ + org.opentest4j.*;resolution:=optional, \ + !org.mockito.internal.creation.bytebuddy.inject,org.mockito.* + + # Don't add the Private-Package header. + # See https://bnd.bndtools.org/instructions/removeheaders.html + -removeheaders: Private-Package + + # Don't add all the extra headers bnd normally adds. + # See https://bnd.bndtools.org/instructions/noextraheaders.html + -noextraheaders: true + """.trimIndent() + ) + } + } + + test { + val java11 = providers.environmentVariable("SIMULATE_JAVA11") + if (java11.isPresent) { + logger.info("$path - use Java11 simulation: $java11") + systemProperty("org.mockito.internal.noUnsafeInjection", java11.get()) + } + } +} + +// +val mockitoExtConfigFiles = listOf( + mockitoExtensionConfigFile(project, "org.mockito.plugins.MockMaker"), + mockitoExtensionConfigFile(project, "org.mockito.plugins.MemberAccessor"), +) + +val createTestResources by tasks.registering { + outputs.files(mockitoExtConfigFiles) + doLast { + // Configure MockMaker from environment (if specified), otherwise use default + configureMockitoExtensionFromCi(project, "org.mockito.plugins.MockMaker", "MOCK_MAKER") + + // Configure MemberAccessor from environment (if specified), otherwise use default + configureMockitoExtensionFromCi(project, "org.mockito.plugins.MemberAccessor", "MEMBER_ACCESSOR") + } +} + +sourceSets.test { + resources { + output.dir( + layout.buildDirectory.dir("generated/resources/ext-config/test"), + "builtBy" to createTestResources + ) + } +} + +fun Task.configureMockitoExtensionFromCi( + project: Project, + mockitoExtension: String, + ciMockitoExtensionEnvVarName: String, +) { + val mockitoExtConfigFile = mockitoExtensionConfigFile(project, mockitoExtension) + val extEnvVar = project.providers.environmentVariable(ciMockitoExtensionEnvVarName) + if (extEnvVar.isPresent && !extEnvVar.get().endsWith("default")) { + logger.info("Using $mockitoExtension ${extEnvVar.get()}") + mockitoExtConfigFile.run { + parentFile.mkdirs() + createNewFile() + writeText(extEnvVar.get()) + } + } else { + logger.info("Using default $mockitoExtension") + } +} + +fun mockitoExtensionConfigFile(project: Project, mockitoExtension: String) = + file(project.layout.buildDirectory.dir("generated/resources/ext-config/test/mockito-extensions/$mockitoExtension")) +// + diff --git a/src/conf/pmd-rules.xml b/mockito-core/src/conf/pmd-rules.xml similarity index 100% rename from src/conf/pmd-rules.xml rename to mockito-core/src/conf/pmd-rules.xml diff --git a/mockito-core/src/main/java/module-info.java b/mockito-core/src/main/java/module-info.java new file mode 100644 index 0000000000..15fbf51d4d --- /dev/null +++ b/mockito-core/src/main/java/module-info.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +module org.mockito { + requires java.instrument; + requires jdk.attach; + requires net.bytebuddy; + requires net.bytebuddy.agent; + requires static junit; + requires static org.hamcrest; + requires static org.objenesis; + requires static org.opentest4j; + requires static jdk.unsupported; + + exports org.mockito; + exports org.mockito.configuration; + exports org.mockito.creation.instance; + exports org.mockito.exceptions.base; + exports org.mockito.exceptions.misusing; + exports org.mockito.exceptions.verification; + exports org.mockito.exceptions.verification.junit; + exports org.mockito.exceptions.verification.opentest4j; + exports org.mockito.hamcrest; + exports org.mockito.invocation; + exports org.mockito.junit; + exports org.mockito.listeners; + exports org.mockito.mock; + exports org.mockito.plugins; + exports org.mockito.quality; + exports org.mockito.session; + exports org.mockito.stubbing; + exports org.mockito.verification; + exports org.mockito.internal to + java.instrument; + exports org.mockito.internal.configuration to + org.mockito.junit.jupiter; + exports org.mockito.internal.configuration.plugins to + org.mockito.junit.jupiter; + exports org.mockito.internal.session to + org.mockito.junit.jupiter; + exports org.mockito.internal.util to + org.mockito.junit.jupiter; +} diff --git a/src/main/java/org/mockito/AdditionalAnswers.java b/mockito-core/src/main/java/org/mockito/AdditionalAnswers.java similarity index 97% rename from src/main/java/org/mockito/AdditionalAnswers.java rename to mockito-core/src/main/java/org/mockito/AdditionalAnswers.java index 0281f32227..63ab9bb483 100644 --- a/src/main/java/org/mockito/AdditionalAnswers.java +++ b/mockito-core/src/main/java/org/mockito/AdditionalAnswers.java @@ -31,7 +31,7 @@ * *

Currently offer answers that can return the parameter of an invocation at a certain position, * along with answers that draw on a strongly typed interface to provide a neater way to write custom answers - * that either return a value or are void (see answer interfaces in {@link org.mockito.stubbing}). + * that either return a value or are void (see answer interfaces in org.mockito.stubbing). * *

See factory methods for more information : {@link #returnsFirstArg}, {@link #returnsSecondArg}, * {@link #returnsLastArg}, {@link #returnsArgAt}, {@link #answer} and {@link #answerVoid} @@ -39,7 +39,7 @@ * @since 1.9.5 */ @SuppressWarnings("unchecked") -public class AdditionalAnswers { +public final class AdditionalAnswers { /** * Returns the first parameter of an invocation. * @@ -276,7 +276,7 @@ public static Answer returnsArgAt(int position) { * This feature suffers from the same drawback as the spy. * The mock will call the delegate if you use regular when().then() stubbing style. * Since the real implementation is called this might have some side effects. - * Therefore you should to use the doReturn|Throw|Answer|CallRealMethod stubbing style. Example: + * Therefore, you should use the doReturn|Throw|Answer|CallRealMethod stubbing style. Example: * *


      *   List listWithDelegate = mock(List.class, AdditionalAnswers.delegatesTo(awesomeList));
@@ -308,7 +308,7 @@ public static  Answer delegatesTo(Object delegate) {
      *   when(mock.foo()).thenReturn(1, 2, 3);
      *
      *   //is equivalent to:
-     *   when(mock.foo()).thenAnswer(new ReturnsElementsOf(Arrays.asList(1, 2, 3)));
+     *   when(mock.foo()).thenAnswer(AdditionalAnswers.returnsElementsOf(Arrays.asList(1, 2, 3)));
      * 
* * @param elements The collection of elements to return. @@ -330,7 +330,6 @@ public static Answer returnsElementsOf(Collection elements) { * * @since 2.8.44 */ - @Incubating public static Answer answersWithDelay(long sleepyTime, Answer answer) { return (Answer) new AnswersWithDelay(sleepyTime, (Answer) answer); } @@ -344,7 +343,6 @@ public static Answer answersWithDelay(long sleepyTime, Answer answer) * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answer(Answer1 answer) { return toAnswer(answer); } @@ -357,7 +355,6 @@ public static Answer answer(Answer1 answer) { * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answerVoid(VoidAnswer1 answer) { return toAnswer(answer); } @@ -372,7 +369,6 @@ public static Answer answerVoid(VoidAnswer1 answer) { * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answer(Answer2 answer) { return toAnswer(answer); } @@ -386,7 +382,6 @@ public static Answer answer(Answer2 answer) { * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answerVoid(VoidAnswer2 answer) { return toAnswer(answer); } @@ -402,7 +397,6 @@ public static Answer answerVoid(VoidAnswer2 answer) { * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answer(Answer3 answer) { return toAnswer(answer); } @@ -417,7 +411,6 @@ public static Answer answer(Answer3 answer) { * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answerVoid(VoidAnswer3 answer) { return toAnswer(answer); } @@ -434,7 +427,6 @@ public static Answer answerVoid(VoidAnswer3 answer) { * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answer(Answer4 answer) { return toAnswer(answer); } @@ -450,7 +442,6 @@ public static Answer answer(Answer4 answer) { * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answerVoid(VoidAnswer4 answer) { return toAnswer(answer); } @@ -468,7 +459,6 @@ public static Answer answerVoid(VoidAnswer4 answe * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answer(Answer5 answer) { return toAnswer(answer); } @@ -486,7 +476,6 @@ public static Answer answer(Answer5 answ * @return the answer object to use * @since 2.1.0 */ - @Incubating public static Answer answerVoid(VoidAnswer5 answer) { return toAnswer(answer); } @@ -506,7 +495,6 @@ public static Answer answerVoid(VoidAnswer5 * @return the answer object to use * @since 2.26.0 */ - @Incubating public static Answer answer(Answer6 answer) { return toAnswer(answer); } @@ -525,8 +513,9 @@ public static Answer answer(Answer6 Answer answerVoid(VoidAnswer6 answer) { return toAnswer(answer); } + + private AdditionalAnswers() {} } diff --git a/src/main/java/org/mockito/AdditionalMatchers.java b/mockito-core/src/main/java/org/mockito/AdditionalMatchers.java similarity index 99% rename from src/main/java/org/mockito/AdditionalMatchers.java rename to mockito-core/src/main/java/org/mockito/AdditionalMatchers.java index 319f92e304..2cb71c6a10 100644 --- a/src/main/java/org/mockito/AdditionalMatchers.java +++ b/mockito-core/src/main/java/org/mockito/AdditionalMatchers.java @@ -16,11 +16,11 @@ import org.mockito.internal.matchers.LessThan; /** - * See {@link Matchers} for general info about matchers. + * See {@link ArgumentMatchers} for general info about matchers. *

* AdditionalMatchers provides rarely used matchers, kept only for somewhat compatibility with EasyMock. * Use additional matchers very judiciously because they may impact readability of a test. - * It is recommended to use matchers from {@link Matchers} and keep stubbing and verification simple. + * It is recommended to use matchers from {@link ArgumentMatchers} and keep stubbing and verification simple. *

* Example of using logical and(), not(), or() matchers: * @@ -38,7 +38,7 @@ * Scroll down to see all methods - full list of matchers. */ @SuppressWarnings("ALL") -public class AdditionalMatchers { +public final class AdditionalMatchers { /** * argument greater than or equal the given value. @@ -1054,4 +1054,6 @@ public static float eq(float value, float delta) { private static void reportMatcher(ArgumentMatcher matcher) { mockingProgress().getArgumentMatcherStorage().reportMatcher(matcher); } + + private AdditionalMatchers() {} } diff --git a/src/main/java/org/mockito/Answers.java b/mockito-core/src/main/java/org/mockito/Answers.java similarity index 87% rename from src/main/java/org/mockito/Answers.java rename to mockito-core/src/main/java/org/mockito/Answers.java index 5cbb1f71e6..30dc307437 100644 --- a/src/main/java/org/mockito/Answers.java +++ b/mockito-core/src/main/java/org/mockito/Answers.java @@ -24,7 +24,7 @@ * * This is not the full list of Answers available in Mockito. Some interesting answers can be found in org.mockito.stubbing.answers package. */ -public enum Answers implements Answer{ +public enum Answers implements Answer { /** * The default configured answer of every mock. * @@ -52,7 +52,6 @@ public enum Answers implements Answer{ */ RETURNS_MOCKS(new ReturnsMocks()), - /** * An answer that returns deep stubs (not mocks). * @@ -78,8 +77,7 @@ public enum Answers implements Answer{ * * @see org.mockito.Mockito#RETURNS_SELF */ - RETURNS_SELF(new TriesToReturnSelf()) - ; + RETURNS_SELF(new TriesToReturnSelf()); private final Answer implementation; @@ -87,15 +85,7 @@ public enum Answers implements Answer{ this.implementation = implementation; } - /** - * @deprecated as of 2.1.0 Use the enum-constant directly, instead of this getter. This method will be removed in a future release
- * E.g. instead of Answers.CALLS_REAL_METHODS.get() use Answers.CALLS_REAL_METHODS . - */ - @Deprecated - public Answer get() { - return this; - } - + @Override public Object answer(InvocationOnMock invocation) throws Throwable { return implementation.answer(invocation); } diff --git a/mockito-core/src/main/java/org/mockito/ArgumentCaptor.java b/mockito-core/src/main/java/org/mockito/ArgumentCaptor.java new file mode 100644 index 0000000000..863c9a29b4 --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/ArgumentCaptor.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2007 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import static org.mockito.internal.util.Primitives.defaultValue; + +import java.util.List; + +import org.mockito.internal.matchers.CapturingMatcher; + +/** + * Use it to capture argument values for further assertions. + * + *

+ * Mockito verifies argument values in natural java style: by using an equals() method. + * This is also the recommended way of matching arguments because it makes tests clean and simple. + * In some situations though, it is helpful to assert on certain arguments after the actual verification. + * For example: + *


+ *   ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
+ *   verify(mock).doSomething(argument.capture());
+ *   assertEquals("John", argument.getValue().getName());
+ * 
+ * + * Example of capturing varargs: + *

+ *   //capturing varargs:
+ *   ArgumentCaptor<Person> varArgs = ArgumentCaptor.forClass(Person.class);
+ *   verify(mock).varArgMethod(varArgs.capture());
+ *   List expected = asList(new Person("John"), new Person("Jane"));
+ *   assertEquals(expected, varArgs.getAllValues());
+ * 
+ * + *

+ * Warning: it is recommended to use ArgumentCaptor with verification but not with stubbing. + * Using ArgumentCaptor with stubbing may decrease test readability because captor is created + * outside of assertion (aka verify or 'then') blocks. + * It may also reduce defect localization because if the stubbed method was not called, then no argument is captured. + * + *

+ * In a way ArgumentCaptor is related to custom argument matchers (see javadoc for {@link ArgumentMatcher} class). + * Both techniques can be used for making sure certain arguments were passed to mock objects. + * However, ArgumentCaptor may be a better fit if: + *

    + *
  • custom argument matcher is not likely to be reused
  • + *
  • you just need it to assert on argument values to complete verification
  • + *
+ * Custom argument matchers via {@link ArgumentMatcher} are usually better for stubbing. + * + *

+ * This utility class will perform type checking on the generic type (since Mockito 5.0.0). + *

+ * There is an annotation that you might find useful: @{@link Captor} + *

+ * See the full documentation on Mockito in javadoc for {@link Mockito} class. + * + * @see Captor + * @since 1.8.0 + */ +@CheckReturnValue +public class ArgumentCaptor { + + private final CapturingMatcher capturingMatcher; + private final Class clazz; + + private ArgumentCaptor(Class clazz) { + this.clazz = clazz; + this.capturingMatcher = new CapturingMatcher<>(clazz); + } + + /** + * Use it to capture the argument. This method must be used inside of verification. + *

+ * Internally, this method registers a special implementation of an {@link ArgumentMatcher}. + * This argument matcher stores the argument value so that you can use it later to perform assertions. + *

+ * See examples in javadoc for {@link ArgumentCaptor} class. + * + * @return null or default values + */ + public T capture() { + T ignored = Mockito.argThat(capturingMatcher); + return defaultValue(clazz); + } + + /** + * Returns the captured value of the argument. When capturing varargs use {@link #getAllValues()}. + *

+ * If verified method was called multiple times then this method returns the latest captured value. + *

+ * See examples in javadoc for {@link ArgumentCaptor} class. + * + * @return captured argument value + */ + public T getValue() { + return this.capturingMatcher.getLastValue(); + } + + /** + * Returns all captured values. Use it when capturing varargs or when the verified method was called multiple times. + * When varargs method was called multiple times, this method returns merged list of all values from all invocations. + *

+ * Example: + *


+     *   mock.doSomething(new Person("John");
+     *   mock.doSomething(new Person("Jane");
+     *
+     *   ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
+     *   verify(mock, times(2)).doSomething(peopleCaptor.capture());
+     *
+     *   List<Person> capturedPeople = peopleCaptor.getAllValues();
+     *   assertEquals("John", capturedPeople.get(0).getName());
+     *   assertEquals("Jane", capturedPeople.get(1).getName());
+     * 
+ * + * Example of capturing varargs: + *

+     *   mock.countPeople(new Person("John"), new Person("Jane"); //vararg method
+     *
+     *   ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
+     *
+     *   verify(mock).countPeople(peopleCaptor.capture());
+     *
+     *   List expected = asList(new Person("John"), new Person("Jane"));
+     *   assertEquals(expected, peopleCaptor.getAllValues());
+     * 
+ * See more examples in javadoc for {@link ArgumentCaptor} class. + * + * @return captured argument value + */ + public List getAllValues() { + return this.capturingMatcher.getAllValues(); + } + + /** + * Build a new ArgumentCaptor. + *

+ * An ArgumentCaptor will perform type checks (since Mockito 5.0.0). + * + * @param clazz Type matching the parameter to be captured. + * @param Type of clazz + * @param Type of object captured by the newly built ArgumentCaptor + * @return A new ArgumentCaptor + */ + public static ArgumentCaptor forClass(Class clazz) { + return new ArgumentCaptor<>(clazz); + } + + /** + * Build a new ArgumentCaptor by inferring the class type. + *

+ * This enables inferring the generic type of an argument captor without + * providing a raw class reference, which enables working around generic + * limitations of the Java compiler without producing compile-time warnings + * unlike {@link #forClass} which would require explicit casting or warning + * suppression. + *

+ * Example usage: + * + *


+     *   // Given
+     *   UserRepository repository = mock();
+     *   UserService service = new UserService(repository);
+     *
+     *   Map<String, User> expectedUsers = Map.of(
+     *       "12345", new User("12345", "Bob"),
+     *       "45678", new User("45678", "Dave")
+     *   );
+     *
+     *   ArgumentCaptor<Map<String, User>> captor = ArgumentCaptor.captor();
+     *
+     *   doNothing().when(repository).storeUsers(captor.capture());
+     *
+     *   // When
+     *   service.createUsers(List.of(
+     *       new User("12345", "Bob"),
+     *       new User("45678", "Dave")
+     *   ));
+     *
+     *   // Then
+     *   Map<String, User> actualUsers = captor.getValue();
+     *
+     *   assertThat(expectedUsers).isEqualTo(actualUsers);
+     * 
+ * + * @param reified do not pass any value here. This is used to trick the compiler + * into reifying the return type without needing casts. + * @param the type of argument to be captured by this captor. + * @return A new ArgumentCaptor. + * @throws IllegalArgumentException if any arguments are passed to this method. + * @since 5.7.0 + */ + @SafeVarargs + @SuppressWarnings({"varargs", "unchecked"}) + public static ArgumentCaptor captor(U... reified) { + if (reified == null || reified.length > 0) { + throw new IllegalArgumentException("Do not provide any arguments to the 'captor' call"); + } + + return forClass((Class) reified.getClass().getComponentType()); + } + + /** + * Get the raw class being captured. + * + * @return the raw class that is being captured by this captor. + */ + Class getCaptorType() { + return clazz; + } +} diff --git a/mockito-core/src/main/java/org/mockito/ArgumentMatcher.java b/mockito-core/src/main/java/org/mockito/ArgumentMatcher.java new file mode 100644 index 0000000000..3c8ccdea00 --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/ArgumentMatcher.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2016 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +/** + * Allows creating customized argument matchers. + * This API was changed in Mockito 2.1.0 in an effort to decouple Mockito from Hamcrest + * and reduce the risk of version incompatibility. + * Migration guide is included close to the bottom of this javadoc. + *

+ * For non-trivial method arguments used in stubbing or verification, you have the following options + * (in no particular order): + *

    + *
  • refactor the code so that the interactions with collaborators are easier to test with mocks. + * Perhaps it is possible to pass a different argument to the method so that mocking is easier? + * If stuff is hard to test it usually indicates the design could be better, so do refactor for testability! + *
  • + *
  • don't match the argument strictly, just use one of the lenient argument matchers like + * {@link Mockito#notNull()}. Some times it is better to have a simple test that works than + * a complicated test that seem to work. + *
  • + *
  • implement equals() method in the objects that are used as arguments to mocks. + * Mockito naturally uses equals() for argument matching. + * Many times, this is option is clean and simple. + *
  • + *
  • use {@link ArgumentCaptor} to capture the arguments and perform assertions on their state. + * Useful when you need to verify the arguments. Captor is not useful if you need argument matching for stubbing. + * Many times, this option leads to clean and readable tests with fine-grained validation of arguments. + *
  • + *
  • use customized argument matchers by implementing {@link ArgumentMatcher} interface + * and passing the implementation to the {@link Mockito#argThat} method. + * This option is useful if custom matcher is needed for stubbing and can be reused a lot. + * Note that {@link Mockito#argThat} demonstrates NullPointerException auto-unboxing caveat. + *
  • + *
  • use an instance of hamcrest matcher and pass it to + * {@link org.mockito.hamcrest.MockitoHamcrest#argThat(org.hamcrest.Matcher)} + * Useful if you already have a hamcrest matcher. Reuse and win! + * Note that {@link org.mockito.hamcrest.MockitoHamcrest#argThat(org.hamcrest.Matcher)} demonstrates NullPointerException auto-unboxing caveat. + *
  • + *
  • Java 8 only - use a lambda in place of an {@link ArgumentMatcher} since {@link ArgumentMatcher} + * is effectively a functional interface. A lambda can be used with the {@link Mockito#argThat} method.
  • + *
+ * + *

+ * Implementations of this interface can be used with {@link ArgumentMatchers#argThat} method. + * Use toString() method for description of the matcher + * - it is printed in verification errors. + * + *


+ * class ListOfTwoElements implements ArgumentMatcher<List> {
+ *     public boolean matches(List list) {
+ *         return list.size() == 2;
+ *     }
+ *     public String toString() {
+ *         //printed in verification errors
+ *         return "[list of 2 elements]";
+ *     }
+ * }
+ *
+ * List mock = mock(List.class);
+ *
+ * when(mock.addAll(argThat(new ListOfTwoElements()))).thenReturn(true);
+ *
+ * mock.addAll(Arrays.asList("one", "two"));
+ *
+ * verify(mock).addAll(argThat(new ListOfTwoElements()));
+ * 
+ * + * To keep it readable you can extract method, e.g: + * + *

+ *   verify(mock).addAll(argThat(new ListOfTwoElements()));
+ *   //becomes
+ *   verify(mock).addAll(listOfTwoElements());
+ * 
+ * + * In Java 8 you can treat ArgumentMatcher as a functional interface + * and use a lambda, e.g.: + * + *

+ *   verify(mock).addAll(argThat(list -> list.size() == 2));
+ * 
+ * + *

+ * Read more about other matchers in javadoc for {@link ArgumentMatchers} class. + *

2.1.0 migration guide

+ * + * All existing custom implementations of ArgumentMatcher will no longer compile. + * All locations where hamcrest matchers are passed to argThat() will no longer compile. + * There are 2 approaches to fix the problems: + *
    + *
  • a) Refactor the hamcrest matcher to Mockito matcher: + * Use "implements ArgumentMatcher" instead of "extends ArgumentMatcher". + * Then refactor describeTo() method into toString() method. + *
  • + *
  • + * b) Use org.mockito.hamcrest.MockitoHamcrest.argThat() instead of Mockito.argThat(). + * Ensure that there is hamcrest dependency on classpath + * (Mockito does not depend on hamcrest any more). + * + *
  • + *
+ * What option is right for you? If you don't mind having a compile-time dependency for Hamcrest, + * then the second option is probably right for you. + * Your choice should not have a big impact and is fully reversible - + * you can choose different option in future (and refactor the code)! + * + * @param type of argument + * @since 2.1.0 + */ +@FunctionalInterface +public interface ArgumentMatcher { + + /** + * Informs if this matcher accepts the given argument. + *

+ * The method should never assert if the argument doesn't match. It + * should only return false. + *

+ * See the example in the top level javadoc for {@link ArgumentMatcher} + * + * @param argument + * the argument + * @return true if this matcher accepts the given argument. + */ + boolean matches(T argument); + + /** + * The type of the argument this matcher matches. + * + *

This method is used to differentiate between a matcher used to match a raw vararg array parameter + * from a matcher used to match a single value passed as a vararg parameter. + * + *

Where the matcher: + *

    + *
  • is at the parameter index of a vararg parameter
  • + *
  • is the last matcher passed
  • + *
  • this method returns a type assignable to the vararg parameter's raw type, i.e. its array type.
  • + *
+ * + * ...then the matcher is matched against the raw vararg parameter, rather than the first element of the raw parameter. + * + *

For example: + * + *


+     *  // Given vararg method with signature:
+     *  int someVarargMethod(String... args);
+     *
+     *  // The following will match invocations with any number of parameters, i.e. any number of elements in the raw array.
+     *  mock.someVarargMethod(isA(String[].class));
+     *
+     *  // The following will match invocations with a single parameter, i.e. one string in the raw array.
+     *  mock.someVarargMethod(isA(String.class));
+     *
+     *  // The following will match invocations with two parameters, i.e. two strings in the raw array
+     *  mock.someVarargMethod(isA(String.class), isA(String.class));
+     * 
+ * + *

Only matcher implementations that can conceptually match a raw vararg parameter should override this method. + * + * @return the type this matcher handles. The default value of {@link Void} means the type is not known. + * @since 4.11.0 + */ + default Class type() { + return Void.class; + } +} diff --git a/mockito-core/src/main/java/org/mockito/ArgumentMatchers.java b/mockito-core/src/main/java/org/mockito/ArgumentMatchers.java new file mode 100644 index 0000000000..05580a7c29 --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/ArgumentMatchers.java @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2016 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress; +import static org.mockito.internal.util.Primitives.defaultValue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.regex.Pattern; + +import org.mockito.internal.matchers.Any; +import org.mockito.internal.matchers.Contains; +import org.mockito.internal.matchers.EndsWith; +import org.mockito.internal.matchers.Equals; +import org.mockito.internal.matchers.InstanceOf; +import org.mockito.internal.matchers.Matches; +import org.mockito.internal.matchers.NotNull; +import org.mockito.internal.matchers.Null; +import org.mockito.internal.matchers.Same; +import org.mockito.internal.matchers.StartsWith; +import org.mockito.internal.matchers.apachecommons.ReflectionEquals; +import org.mockito.internal.util.Primitives; + +/** + * Allow flexible verification or stubbing. See also {@link AdditionalMatchers}. + * + *


+ * //stubbing using anyInt() argument matcher
+ * when(mockedList.get(anyInt())).thenReturn("element");
+ *
+ * //following prints "element"
+ * System.out.println(mockedList.get(999));
+ *
+ * //you can also verify using argument matcher
+ * verify(mockedList).get(anyInt());
+ * 
+ * + *

+ * Since Mockito any(Class) and anyInt family matchers perform a type check, thus they won't + * match null arguments. Instead use the isNull matcher. + * + *


+ * // stubbing using anyBoolean() argument matcher
+ * when(mock.dryRun(anyBoolean())).thenReturn("state");
+ *
+ * // below the stub won't match, and won't return "state"
+ * mock.dryRun(null);
+ *
+ * // either change the stub
+ * when(mock.dryRun(isNull())).thenReturn("state");
+ * mock.dryRun(null); // ok
+ *
+ * // or fix the code ;)
+ * when(mock.dryRun(anyBoolean())).thenReturn("state");
+ * mock.dryRun(true); // ok
+ *
+ * 
+ * + * The same apply for verification. + *

+ * + * + * Scroll down to see all methods - full list of matchers. + * + *

+ * Warning:
+ * + * If you are using argument matchers, all arguments have to be provided by matchers. + * + * E.g: (example shows verification but the same applies to stubbing): + *

+ * + *

+ * verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
+ * //above is correct - eq() is also an argument matcher
+ *
+ * verify(mock).someMethod(anyInt(), anyString(), "third argument");
+ * //above is incorrect - exception will be thrown because third argument is given without argument matcher.
+ * 
+ * + *

+ * Matcher methods like any(), eq() do not return matchers. + * Internally, they record a matcher on a stack and return a dummy value (usually null). + * This implementation is due to static type safety imposed by java compiler. + * The consequence is that you cannot use any(), eq() methods outside of verified/stubbed method. + *

+ * + *

Additional matchers

+ *

+ * The class {@link AdditionalMatchers} offers rarely used matchers, although they can be useful, when + * it is useful to combine multiple matchers or when it is useful to negate a matcher necessary. + *

+ * + *

Custom Argument ArgumentMatchers

+ *

+ * It is important to understand the use cases and available options for dealing with non-trivial arguments + * before implementing custom argument matchers. This way, you can select the best possible approach + * for given scenario and produce highest quality test (clean and maintainable). + * Please read on in the javadoc for {@link ArgumentMatcher} to learn about approaches and see the examples. + *

+ * + * @see AdditionalMatchers + */ +@CheckReturnValue +@SuppressWarnings("unchecked") +public class ArgumentMatchers { + + /** + * Matches anything, including nulls. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + *

+ * Notes :
+ *

    + *
  • For primitive types use {@link #anyChar()} family or {@link #isA(Class)} or {@link #any(Class)}.
  • + *
  • Since Mockito 2.1.0 {@link #any(Class)} is not anymore an alias of this method.
  • + *
  • Since Mockito 5.0.0 this no longer matches varargs. Use {@link #any(Class)} instead.
  • + *
+ *

+ * + * @return null. + * + * @see #any(Class) + * @see #anyChar() + * @see #anyInt() + * @see #anyBoolean() + */ + public static T any() { + reportMatcher(Any.ANY); + return null; + } + + /** + * Matches any object of given type, excluding nulls. + * + *

+ * This matcher will perform a type check with the given type, thus excluding values. + * See examples in javadoc for {@link ArgumentMatchers} class. + * + * This is an alias of: {@link #isA(Class)}} + *

+ * + *

+ * Since Mockito 2.1.0, only allow non-null instance of , thus null is not anymore a valid value. + * As reference are nullable, the suggested API to match null + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

Notes :
+ *

    + *
  • For primitive types use {@link #anyChar()} family.
  • + *
  • Since Mockito 2.1.0 this method will perform a type check thus null values are not authorized.
  • + *
  • Since Mockito 2.1.0 {@link #any()} is no longer an alias of this method.
  • + *
  • Since Mockito 5.0.0 this method can match varargs if the array type is specified, for example any(String[].class).
  • + *
+ *

+ * + * @param The accepted type + * @param type the class of the accepted type. + * @return null. + * @see #any() + * @see #isA(Class) + * @see #notNull() + * @see #isNull() + */ + public static T any(Class type) { + reportMatcher(new InstanceOf(type, "")); + return defaultValue(type); + } + + /** + * Object argument that implements the given class. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param the accepted type. + * @param type the class of the accepted type. + * @return null. + * @see #any(Class) + */ + public static T isA(Class type) { + reportMatcher(new InstanceOf(type)); + return defaultValue(type); + } + + /** + * Any boolean or non-null Boolean + * + *

+ * Since Mockito 2.1.0, only allow valued Boolean, thus null is not anymore a valid value. + * As primitive wrappers are nullable, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return false. + * @see #isNull() + */ + public static boolean anyBoolean() { + reportMatcher(new InstanceOf(Boolean.class, "")); + return false; + } + + /** + * Any byte or non-null Byte. + * + *

+ * Since Mockito 2.1.0, only allow valued Byte, thus null is not anymore a valid value. + * As primitive wrappers are nullable, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return 0. + * @see #isNull() + */ + public static byte anyByte() { + reportMatcher(new InstanceOf(Byte.class, "")); + return 0; + } + + /** + * Any char or non-null Character. + * + *

+ * Since Mockito 2.1.0, only allow valued Character, thus null is not anymore a valid value. + * As primitive wrappers are nullable, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return 0. + * @see #isNull() + */ + public static char anyChar() { + reportMatcher(new InstanceOf(Character.class, "")); + return 0; + } + + /** + * Any int or non-null Integer. + * + *

+ * Since Mockito 2.1.0, only allow valued Integer, thus null is not anymore a valid value. + * As primitive wrappers are nullable, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return 0. + * @see #isNull() + */ + public static int anyInt() { + reportMatcher(new InstanceOf(Integer.class, "")); + return 0; + } + + /** + * Any long or non-null Long. + * + *

+ * Since Mockito 2.1.0, only allow valued Long, thus null is not anymore a valid value. + * As primitive wrappers are nullable, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return 0. + * @see #isNull() + */ + public static long anyLong() { + reportMatcher(new InstanceOf(Long.class, "")); + return 0; + } + + /** + * Any float or non-null Float. + * + *

+ * Since Mockito 2.1.0, only allow valued Float, thus null is not anymore a valid value. + * As primitive wrappers are nullable, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return 0. + * @see #isNull() + */ + public static float anyFloat() { + reportMatcher(new InstanceOf(Float.class, "")); + return 0; + } + + /** + * Any double or non-null Double. + * + *

+ * Since Mockito 2.1.0, only allow valued Double, thus null is not anymore a valid value. + * As primitive wrappers are nullable, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return 0. + * @see #isNull() + */ + public static double anyDouble() { + reportMatcher(new InstanceOf(Double.class, "")); + return 0; + } + + /** + * Any short or non-null Short. + * + *

+ * Since Mockito 2.1.0, only allow valued Short, thus null is not anymore a valid value. + * As primitive wrappers are nullable, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return 0. + * @see #isNull() + */ + public static short anyShort() { + reportMatcher(new InstanceOf(Short.class, "")); + return 0; + } + + /** + * Any non-null String + * + *

+ * Since Mockito 2.1.0, only allow non-null String. + * As this is a nullable reference, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return empty String ("") + * @see #isNull() + */ + public static String anyString() { + reportMatcher(new InstanceOf(String.class, "")); + return ""; + } + + /** + * Any non-null List. + * + *

+ * Since Mockito 2.1.0, only allow non-null List. + * As this is a nullable reference, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return empty List. + * @see #isNull() + */ + public static List anyList() { + reportMatcher(new InstanceOf(List.class, "")); + return new ArrayList(0); + } + + /** + * Any non-null Set. + * + *

+ * Since Mockito 2.1.0, only allow non-null Set. + * As this is a nullable reference, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return empty Set + * @see #isNull() + */ + public static Set anySet() { + reportMatcher(new InstanceOf(Set.class, "")); + return new HashSet(0); + } + + /** + * Any non-null Map. + * + *

+ * Since Mockito 2.1.0, only allow non-null Map. + * As this is a nullable reference, the suggested API to match null wrapper + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return empty Map. + * @see #isNull() + */ + public static Map anyMap() { + reportMatcher(new InstanceOf(Map.class, "")); + return new HashMap(0); + } + + /** + * Any non-null Collection. + * + *

+ * Since Mockito 2.1.0, only allow non-null Collection. + * As this is a nullable reference, the suggested API to match null + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return empty Collection. + * @see #isNull() + */ + public static Collection anyCollection() { + reportMatcher(new InstanceOf(Collection.class, "")); + return new ArrayList(0); + } + + /** + * Any non-null Iterable. + * + *

+ * Since Mockito 2.1.0, only allow non-null Iterable. + * As this is a nullable reference, the suggested API to match null + * would be {@link #isNull()}. We felt this change would make test harnesses much safer than they were with Mockito + * 1.x. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class. + *

+ * + * @return empty Iterable. + * @see #isNull() + * @since 2.1.0 + */ + public static Iterable anyIterable() { + reportMatcher(new InstanceOf(Iterable.class, "")); + return new ArrayList(0); + } + + /** + * boolean argument that is equal to the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @return 0. + */ + public static boolean eq(boolean value) { + reportMatcher(new Equals(value)); + return false; + } + + /** + * byte argument that is equal to the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @return 0. + */ + public static byte eq(byte value) { + reportMatcher(new Equals(value)); + return 0; + } + + /** + * char argument that is equal to the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @return 0. + */ + public static char eq(char value) { + reportMatcher(new Equals(value)); + return 0; + } + + /** + * double argument that is equal to the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @return 0. + */ + public static double eq(double value) { + reportMatcher(new Equals(value)); + return 0; + } + + /** + * float argument that is equal to the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @return 0. + */ + public static float eq(float value) { + reportMatcher(new Equals(value)); + return 0; + } + + /** + * int argument that is equal to the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @return 0. + */ + public static int eq(int value) { + reportMatcher(new Equals(value)); + return 0; + } + + /** + * long argument that is equal to the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @return 0. + */ + public static long eq(long value) { + reportMatcher(new Equals(value)); + return 0; + } + + /** + * short argument that is equal to the given value. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param value the given value. + * @return 0. + */ + public static short eq(short value) { + reportMatcher(new Equals(value)); + return 0; + } + + /** + * Object argument that is equal to the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @return null. + */ + public static T eq(T value) { + reportMatcher(new Equals(value)); + if (value == null) return null; + return (T) Primitives.defaultValue(value.getClass()); + } + + /** + * Object argument that is reflection-equal to the given value with support for excluding + * selected fields from a class. + * + *

+ * This matcher can be used when equals() is not implemented on compared objects. + * Matcher uses java reflection API to compare fields of wanted and actual object. + *

+ * + *

+ * Works similarly to EqualsBuilder.reflectionEquals(this, other, excludeFields) from + * apache commons library. + *

+ * Warning The equality check is shallow! + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param value the given value. + * @param excludeFields fields to exclude, if field does not exist it is ignored. + * @return null. + */ + public static T refEq(T value, String... excludeFields) { + reportMatcher(new ReflectionEquals(value, excludeFields)); + return null; + } + + /** + * Object argument that is the same as the given value. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param the type of the object, it is passed through to prevent casts. + * @param value the given value. + * @return null. + */ + public static T same(T value) { + reportMatcher(new Same(value)); + if (value == null) { + return null; + } + return (T) Primitives.defaultValue(value.getClass()); + } + + /** + * null argument. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @return null. + * @see #isNotNull() + */ + public static T isNull() { + reportMatcher(Null.NULL); + return null; + } + + /** + * null argument. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param type the type of the argument being matched. + * @return null. + * @see #isNotNull(Class) + * @since 4.11.0 + */ + public static T isNull(Class type) { + reportMatcher(new Null<>(type)); + return null; + } + + /** + * Not null argument. + * + *

+ * Alias to {@link ArgumentMatchers#isNotNull()} + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @return null. + */ + public static T notNull() { + reportMatcher(NotNull.NOT_NULL); + return null; + } + + /** + * Not null argument. + * + *

+ * Alias to {@link ArgumentMatchers#isNotNull()} + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param type the type of the argument being matched. + * @return null. + * @since 4.11.0 + */ + public static T notNull(Class type) { + reportMatcher(new NotNull<>(type)); + return null; + } + + /** + * Not null argument. + * + *

+ * Alias to {@link ArgumentMatchers#notNull()} + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @return null. + * @see #isNull() + */ + public static T isNotNull() { + return notNull(); + } + + /** + * Not null argument. + * + *

+ * Alias to {@link ArgumentMatchers#notNull(Class)} + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param type the type of the argument being matched. + * @return null. + * @see #isNull() + * @since 4.11.0 + */ + public static T isNotNull(Class type) { + return notNull(type); + } + + /** + * Argument that is either null or of the given type. + * + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + *

+ * + * @param clazz Type to avoid casting + * @return null. + */ + public static T nullable(Class clazz) { + AdditionalMatchers.or(isNull(), isA(clazz)); + return Primitives.defaultValue(clazz); + } + + /** + * String argument that contains the given substring. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param substring the substring. + * @return empty String (""). + */ + public static String contains(String substring) { + reportMatcher(new Contains(substring)); + return ""; + } + + /** + * String argument that matches the given regular expression. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param regex the regular expression. + * @return empty String (""). + * + * @see AdditionalMatchers#not(boolean) + */ + public static String matches(String regex) { + reportMatcher(new Matches(regex)); + return ""; + } + + /** + * Pattern argument that matches the given regular expression. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param pattern the regular expression pattern. + * @return empty String (""). + * + * @see AdditionalMatchers#not(boolean) + */ + public static String matches(Pattern pattern) { + reportMatcher(new Matches(pattern)); + return ""; + } + + /** + * String argument that ends with the given suffix. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param suffix the suffix. + * @return empty String (""). + */ + public static String endsWith(String suffix) { + reportMatcher(new EndsWith(suffix)); + return ""; + } + + /** + * String argument that starts with the given prefix. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param prefix the prefix. + * @return empty String (""). + */ + public static String startsWith(String prefix) { + reportMatcher(new StartsWith(prefix)); + return ""; + } + + /** + * Allows creating custom argument matchers. + * + *

+ * This API has changed in 2.1.0, please read {@link ArgumentMatcher} for rationale and migration guide. + * NullPointerException auto-unboxing caveat is described below. + *

+ * + *

+ * It is important to understand the use cases and available options for dealing with non-trivial arguments + * before implementing custom argument matchers. This way, you can select the best possible approach + * for given scenario and produce highest quality test (clean and maintainable). + * Please read the documentation for {@link ArgumentMatcher} to learn about approaches and see the examples. + *

+ * + *

+ * NullPointerException auto-unboxing caveat. + * In rare cases when matching primitive parameter types you *must* use relevant intThat(), floatThat(), etc. method. + * This way you will avoid NullPointerException during auto-unboxing. + * Due to how java works we don't really have a clean way of detecting this scenario and protecting the user from this problem. + * Hopefully, the javadoc describes the problem and solution well. + * If you have an idea how to fix the problem, let us know via the mailing list or the issue tracker. + *

+ * + *

+ * See examples in javadoc for {@link ArgumentMatcher} class + *

+ * + * @param matcher decides whether argument matches + * @return null. + */ + public static T argThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return null; + } + + /** + * Allows creating custom argument matchers where matching is considered successful when the consumer given by parameter does not throw an exception. + *

+ * Typically used with {@link Mockito#verify(Object)} to execute assertions on parameters passed to the verified method invocation. + * + * @param consumer executes assertions on the verified argument + * @return null. + */ + public static T assertArg(Consumer consumer) { + return argThat( + argument -> { + consumer.accept(argument); + return true; + }); + } + + /** + * Allows creating custom argument matchers where matching is considered successful when the consumer given by parameter does not throw an exception. + * Consumer is allowed to throw exception other than RuntimeException + *

+ * Typically used with {@link Mockito#verify(Object)} to execute assertions on parameters passed to the verified method invocation. + * + * @param consumer executes assertions on the verified argument + * @return null. + */ + public static T assertArg(ThrowingConsumer consumer) { + return argThat( + argument -> { + consumer.accept(argument); + return true; + }); + } + + /** + * Allows creating custom char argument matchers. + *

+ * Note that {@link #argThat} will not work with primitive char matchers due to NullPointerException auto-unboxing caveat. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param matcher decides whether argument matches + * @return 0. + */ + public static char charThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return 0; + } + + /** + * Allows creating custom boolean argument matchers. + *

+ * Note that {@link #argThat} will not work with primitive boolean matchers due to NullPointerException auto-unboxing caveat. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param matcher decides whether argument matches + * @return false. + */ + public static boolean booleanThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return false; + } + + /** + * Allows creating custom byte argument matchers. + *

+ * Note that {@link #argThat} will not work with primitive byte matchers due to NullPointerException auto-unboxing caveat. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param matcher decides whether argument matches + * @return 0. + */ + public static byte byteThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return 0; + } + + /** + * Allows creating custom short argument matchers. + *

+ * Note that {@link #argThat} will not work with primitive short matchers due to NullPointerException auto-unboxing caveat. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param matcher decides whether argument matches + * @return 0. + */ + public static short shortThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return 0; + } + + /** + * Allows creating custom int argument matchers. + *

+ * Note that {@link #argThat} will not work with primitive int matchers due to NullPointerException auto-unboxing caveat. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param matcher decides whether argument matches + * @return 0. + */ + public static int intThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return 0; + } + + /** + * Allows creating custom long argument matchers. + *

+ * Note that {@link #argThat} will not work with primitive long matchers due to NullPointerException auto-unboxing caveat. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param matcher decides whether argument matches + * @return 0. + */ + public static long longThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return 0; + } + + /** + * Allows creating custom float argument matchers. + *

+ * Note that {@link #argThat} will not work with primitive float matchers due to NullPointerException auto-unboxing caveat. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param matcher decides whether argument matches + * @return 0. + */ + public static float floatThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return 0; + } + + /** + * Allows creating custom double argument matchers. + *

+ * Note that {@link #argThat} will not work with primitive double matchers due to NullPointerException auto-unboxing caveat. + *

+ * See examples in javadoc for {@link ArgumentMatchers} class + * + * @param matcher decides whether argument matches + * @return 0. + */ + public static double doubleThat(ArgumentMatcher matcher) { + reportMatcher(matcher); + return 0; + } + + private static void reportMatcher(ArgumentMatcher matcher) { + mockingProgress().getArgumentMatcherStorage().reportMatcher(matcher); + } +} diff --git a/src/main/java/org/mockito/BDDMockito.java b/mockito-core/src/main/java/org/mockito/BDDMockito.java similarity index 87% rename from src/main/java/org/mockito/BDDMockito.java rename to mockito-core/src/main/java/org/mockito/BDDMockito.java index b2dbf6e751..d37a07ae93 100644 --- a/src/main/java/org/mockito/BDDMockito.java +++ b/mockito-core/src/main/java/org/mockito/BDDMockito.java @@ -13,7 +13,7 @@ * Behavior Driven Development style of writing tests uses //given //when //then comments as fundamental parts of your test methods. * This is exactly how we write our tests and we warmly encourage you to do so! *

- * Start learning about BDD here: http://en.wikipedia.org/wiki/Behavior_Driven_Development + * Start learning about BDD here: https://en.wikipedia.org/wiki/Behavior-driven_development *

* The problem is that current stubbing api with canonical role of when word does not integrate nicely with //given //when //then comments. * It's because stubbing belongs to given component of the test and not to the when component of the test. @@ -127,9 +127,12 @@ public interface BDDMyOngoingStubbing { * See original {@link OngoingStubbing#thenThrow(Class, Class[])} * @since 2.1.0 */ - // Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation - @SuppressWarnings ({"unchecked", "varargs"}) - BDDMyOngoingStubbing willThrow(Class throwableType, Class... throwableTypes); + // Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array + // creation + @SuppressWarnings({"unchecked", "varargs"}) + BDDMyOngoingStubbing willThrow( + Class throwableType, + Class... throwableTypes); /** * See original {@link OngoingStubbing#thenCallRealMethod()} @@ -176,8 +179,11 @@ public BDDMyOngoingStubbing willThrow(Class throwableTyp return new BDDOngoingStubbingImpl(mockitoOngoingStubbing.thenThrow(throwableType)); } - public BDDMyOngoingStubbing willThrow(Class throwableType, Class... throwableTypes) { - return new BDDOngoingStubbingImpl(mockitoOngoingStubbing.thenThrow(throwableType, throwableTypes)); + public BDDMyOngoingStubbing willThrow( + Class throwableType, + Class... throwableTypes) { + return new BDDOngoingStubbingImpl( + mockitoOngoingStubbing.thenThrow(throwableType, throwableTypes)); } public BDDMyOngoingStubbing willCallRealMethod() { @@ -248,14 +254,6 @@ public interface Then { */ T should(InOrder inOrder, VerificationMode mode); - /** - * @see #verifyZeroInteractions(Object...) - * @since 2.1.0 - * @deprecated Since 3.0.1. Please migrate your code to {@link #shouldHaveNoInteractions()} - */ - @Deprecated - void shouldHaveZeroInteractions(); - /** * @see #verifyNoMoreInteractions(Object...) * @since 2.1.0 @@ -309,14 +307,6 @@ public T should(InOrder inOrder, VerificationMode mode) { return inOrder.verify(mock, mode); } - /** - * @see #verifyZeroInteractions(Object...) - * @since 2.1.0 - */ - public void shouldHaveZeroInteractions() { - verifyZeroInteractions(mock); - } - /** * @see #verifyNoMoreInteractions(Object...) * @since 2.1.0 @@ -351,17 +341,6 @@ public interface BDDStubber { */ BDDStubber will(Answer answer); - /** - * See original {@link Stubber#doNothing()}. - * - * This method will be removed in version 3.0.0 - * - * @since 1.8.0 - * @deprecated as of 2.1.0 please use {@link #willDoNothing()} instead - */ - @Deprecated - BDDStubber willNothing(); - /** * See original {@link Stubber#doNothing()} * @since 1.10.20 @@ -397,8 +376,10 @@ public interface BDDStubber { * See original {@link Stubber#doThrow(Class, Class[])} * @since 2.1.0 */ - @SuppressWarnings ({"unchecked", "varargs"}) - BDDStubber willThrow(Class toBeThrown, Class... nextToBeThrown); + @SuppressWarnings({"unchecked", "varargs"}) + BDDStubber willThrow( + Class toBeThrown, + Class... nextToBeThrown); /** * See original {@link Stubber#doCallRealMethod()} @@ -433,14 +414,6 @@ public BDDStubber will(Answer answer) { return new BDDStubberImpl(mockitoStubber.doAnswer(answer)); } - /** - * @deprecated please use {@link #willDoNothing()} instead - */ - @Deprecated - public BDDStubber willNothing() { - return willDoNothing(); - } - public BDDStubber willDoNothing() { return new BDDStubberImpl(mockitoStubber.doNothing()); } @@ -450,7 +423,8 @@ public BDDStubber willReturn(Object toBeReturned) { } public BDDStubber willReturn(Object toBeReturned, Object... nextToBeReturned) { - return new BDDStubberImpl(mockitoStubber.doReturn(toBeReturned).doReturn(nextToBeReturned)); + return new BDDStubberImpl( + mockitoStubber.doReturn(toBeReturned).doReturn(nextToBeReturned)); } public BDDStubber willThrow(Throwable... toBeThrown) { @@ -461,7 +435,9 @@ public BDDStubber willThrow(Class toBeThrown) { return new BDDStubberImpl(mockitoStubber.doThrow(toBeThrown)); } - public BDDStubber willThrow(Class toBeThrown, Class... nextToBeThrown) { + public BDDStubber willThrow( + Class toBeThrown, + Class... nextToBeThrown) { return new BDDStubberImpl(mockitoStubber.doThrow(toBeThrown, nextToBeThrown)); } @@ -490,7 +466,8 @@ public static BDDStubber willThrow(Class toBeThrown) { * see original {@link Mockito#doThrow(Class)} * @since 1.9.0 */ - public static BDDStubber willThrow(Class toBeThrown, Class... throwableTypes) { + public static BDDStubber willThrow( + Class toBeThrown, Class... throwableTypes) { return new BDDStubberImpl(Mockito.doThrow(toBeThrown, throwableTypes)); } diff --git a/mockito-core/src/main/java/org/mockito/Captor.java b/mockito-core/src/main/java/org/mockito/Captor.java new file mode 100644 index 0000000000..cedd60e242 --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/Captor.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Allows shorthand {@link org.mockito.ArgumentCaptor} creation on fields. + * + *

Example: + *


+ * public class Test{
+ *
+ *    @Captor ArgumentCaptor<AsyncCallback<Foo>> captor;
+ *
+ *    private AutoCloseable closeable;
+ *
+ *    @Before
+ *    public void open() {
+ *       closeable = MockitoAnnotations.openMocks(this);
+ *    }
+ *
+ *    @After
+ *    public void release() throws Exception {
+ *       closeable.close();
+ *    }
+ *
+ *    @Test public void shouldDoSomethingUseful() {
+ *       //...
+ *       verify(mock).doStuff(captor.capture());
+ *       assertEquals("foo", captor.getValue());
+ *    }
+ * }
+ * 
+ * + *

+ * One of the advantages of using @Captor annotation is that you can avoid warnings related capturing complex generic types. + * + * @see ArgumentCaptor + * @since 1.8.3 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Documented +public @interface Captor {} diff --git a/src/main/java/org/mockito/CheckReturnValue.java b/mockito-core/src/main/java/org/mockito/CheckReturnValue.java similarity index 80% rename from src/main/java/org/mockito/CheckReturnValue.java rename to mockito-core/src/main/java/org/mockito/CheckReturnValue.java index 0498c148a8..935b3207f6 100644 --- a/src/main/java/org/mockito/CheckReturnValue.java +++ b/mockito-core/src/main/java/org/mockito/CheckReturnValue.java @@ -9,7 +9,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; - /** * This annotation is not supposed to be used by Mockito end-users. Instead, we * use it to annotate methods for Static Analysis tools, including FindBugs and ErrorProne. @@ -18,15 +17,9 @@ * This annotation is public, because we have to use it in multiple packages. * * @see Findbugs source code - * @see ErrorProne check + * @see ErrorProne check * @since 2.11.4 */ -@Target({ - ElementType.CONSTRUCTOR, - ElementType.METHOD, - ElementType.PACKAGE, - ElementType.TYPE -}) +@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PACKAGE, ElementType.TYPE}) @Retention(RetentionPolicy.CLASS) -public @interface CheckReturnValue { -} +public @interface CheckReturnValue {} diff --git a/mockito-core/src/main/java/org/mockito/DoNotMock.java b/mockito-core/src/main/java/org/mockito/DoNotMock.java new file mode 100644 index 0000000000..fb2de8ecf4 --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/DoNotMock.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Annotation representing a type that should not be mocked. + *

When marking a type {@code @DoNotMock}, you should always point to alternative testing + * solutions such as standard fakes or other testing utilities. + * + * Mockito enforces {@code @DoNotMock} with the {@link org.mockito.plugins.DoNotMockEnforcer}. + * + * If you want to use a custom {@code @DoNotMock} annotation, the {@link org.mockito.plugins.DoNotMockEnforcer} + * will match on annotations with a type ending in "org.mockito.DoNotMock". You can thus place + * your custom annotation in {@code com.my.package.org.mockito.DoNotMock} and Mockito will enforce + * that types annotated by {@code @com.my.package.org.mockito.DoNotMock} can not be mocked. + * + *


+ * @DoNotMock(reason = "Use a real instance instead")
+ * class DoNotMockMe {}
+ * 
+ */ +@Target({TYPE}) +@Retention(RUNTIME) +@Documented +public @interface DoNotMock { + /** + * The reason why the annotated type should not be mocked. + * + *

This should suggest alternative APIs to use for testing objects of this type. + */ + String reason() default "Create a real instance instead."; +} diff --git a/mockito-core/src/main/java/org/mockito/InOrder.java b/mockito-core/src/main/java/org/mockito/InOrder.java new file mode 100644 index 0000000000..ee71ae197c --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/InOrder.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2007 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import static org.mockito.Mockito.times; + +import org.mockito.verification.VerificationMode; + +/** + * Allows verification in order. E.g: + * + *


+ * // Given
+ * First firstMock = mock(First.class);
+ * Second secondMock = mock(Second.class);
+ * InOrder inOrder = inOrder(firstMock, secondMock);
+ *
+ * // When
+ * firstMock.add("was called first");
+ * secondMock.add("was called second");
+ *
+ * // Then
+ * inOrder.verify(firstMock).add("was called first");
+ * inOrder.verify(secondMock).add("was called second");
+ * inOrder.verifyNoMoreInteractions();
+ * 
+ * + * Static mocks can be verified alongside non-static mocks. E.g: + * + *

+ * // Given
+ * First firstMock = mock(First.class);
+ * MockedStatic staticSecondMock = mockStatic(StaticSecond.class);
+ * InOrder inOrder = inOrder(firstMock, StaticSecond.class);
+ *
+ * // When
+ * firstMock.add("was called first");
+ * StaticSecond.doSomething("foobar");
+ *
+ * // Then
+ * inOrder.verify(firstMock).add("was called first");
+ * inOrder.verify(staticSecondMock, () -> StaticSecond.doSomething("foobar"));
+ * inOrder.verifyNoMoreInteractions();
+ * 
+ * + * As of Mockito 1.8.4 you can verifyNoMoreInteractions() in order-sensitive way. Read more: + * {@link InOrder#verifyNoMoreInteractions()}. + *

+ * + * See examples in javadoc for {@link Mockito} class + */ +public interface InOrder { + /** + * Verifies interaction happened once in order. + *

+ * Alias to inOrder.verify(mock, times(1)) + *

+ * Example: + *


+     * InOrder inOrder = inOrder(firstMock, secondMock);
+     *
+     * inOrder.verify(firstMock).someMethod("was called first");
+     * inOrder.verify(secondMock).someMethod("was called second");
+     * 
+ * + * See examples in javadoc for {@link Mockito} class + * + * @param mock to be verified + * + * @return mock object itself + */ + T verify(T mock); + + /** + * Verifies interaction in order. E.g: + * + *

+     * InOrder inOrder = inOrder(firstMock, secondMock);
+     *
+     * inOrder.verify(firstMock, times(2)).someMethod("was called first two times");
+     * inOrder.verify(secondMock, atLeastOnce()).someMethod("was called second at least once");
+     * 
+ * + * See examples in javadoc for {@link Mockito} class + * + * @param mock to be verified + * @param mode for example times(x) or atLeastOnce() + * + * @return mock object itself + */ + T verify(T mock, VerificationMode mode); + + /** + * Verifies static interaction in order, with exactly one number of invocations. + * + * @see #verify(MockedStatic, MockedStatic.Verification, VerificationMode) + */ + default void verify(MockedStatic mockedStatic, MockedStatic.Verification verification) { + verify(mockedStatic, verification, times(1)); + } + + /** + * Verifies static interaction in order. E.g: + * + *

+     * try (MockedStatic mocked = mockStatic(Foo.class)) {
+     *   InOrder inOrder = inOrder(Foo.class);
+     *
+     *   mocked.when(Foo::firstMethod).thenReturn("first");
+     *   mocked.when(Foo::secondMethod).thenReturn("second");
+     *
+     *   assertEquals("first", Foo.firstMethod());
+     *   assertEquals("second", Foo.secondMethod());
+     *
+     *   inOrder.verify(mocked, Foo::firstMethod, times(1));
+     *   inOrder.verify(mocked, Foo::secondMethod, atLeastOnce());
+     * }
+     * 
+ * + * @param mockedStatic static mock to be verified + * @param verification verification to be verified + * @param mode for example times(x) or atLeastOnce() + */ + void verify( + MockedStatic mockedStatic, + MockedStatic.Verification verification, + VerificationMode mode); + + /** + * Verifies that no more interactions happened in order. + * Different from {@link Mockito#verifyNoMoreInteractions(Object...)} because the order of verification matters. + *

+ * Example: + *


+     * mock.foo(); //1st
+     * mock.bar(); //2nd
+     * mock.baz(); //3rd
+     *
+     * InOrder inOrder = inOrder(mock);
+     *
+     * inOrder.verify(mock).bar(); //2n
+     * inOrder.verify(mock).baz(); //3rd (last method)
+     *
+     * //passes because there are no more interactions after last method:
+     * inOrder.verifyNoMoreInteractions();
+     *
+     * //however this fails because 1st method was not verified:
+     * Mockito.verifyNoMoreInteractions(mock);
+     * 
+ */ + void verifyNoMoreInteractions(); +} diff --git a/src/main/java/org/mockito/Incubating.java b/mockito-core/src/main/java/org/mockito/Incubating.java similarity index 75% rename from src/main/java/org/mockito/Incubating.java rename to mockito-core/src/main/java/org/mockito/Incubating.java index 2cdfaddf41..ba209b3c41 100644 --- a/src/main/java/org/mockito/Incubating.java +++ b/mockito-core/src/main/java/org/mockito/Incubating.java @@ -5,6 +5,7 @@ package org.mockito; import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -22,8 +23,13 @@ * and can change before release. * * + * + *

+ * Any components extending a class or interface annotated with this annotation should also + * be considered to be incubating, as the underlying implementation may be subject to future change + * before it is finalized. */ @Retention(RetentionPolicy.RUNTIME) +@Inherited @Documented -public @interface Incubating { -} +public @interface Incubating {} diff --git a/src/main/java/org/mockito/InjectMocks.java b/mockito-core/src/main/java/org/mockito/InjectMocks.java similarity index 87% rename from src/main/java/org/mockito/InjectMocks.java rename to mockito-core/src/main/java/org/mockito/InjectMocks.java index 375c35514d..c804126641 100644 --- a/src/main/java/org/mockito/InjectMocks.java +++ b/mockito-core/src/main/java/org/mockito/InjectMocks.java @@ -22,14 +22,14 @@ * *

* Mockito will try to inject mocks only either by constructor injection, - * setter injection, or property injection in order and as described below. + * property injection or setter injection in order and as described below. * If any of the following strategy fail, then Mockito won't report failure; * i.e. you will have to provide dependencies yourself. *

    *
  1. Constructor injection; the biggest constructor is chosen, * then arguments are resolved with mocks declared in the test only. If the object is successfully created * with the constructor, then Mockito won't try the other strategies. Mockito has decided to no - * corrupt an object if it has a parametered constructor. + * corrupt an object if it has a parameterized constructor. *

    Note: If arguments can not be found, then null is passed. * If non-mockable types are wanted, then constructor injection won't happen. * In these cases, you will have to satisfy dependencies yourself.

  2. @@ -71,8 +71,14 @@ * * public class SampleBaseTestCase { * - * @Before public void initMocks() { - * MockitoAnnotations.initMocks(this); + * private AutoCloseable closeable; + * + * @Before public void openMocks() { + * closeable = MockitoAnnotations.openMocks(this); + * } + * + * @After public void releaseMocks() throws Exception { + * closeable.close(); * } * } *
    @@ -141,11 +147,10 @@ *

    * *

    - * MockitoAnnotations.initMocks(this) method has to be called to initialize annotated objects. - * In above example, initMocks() is called in @Before (JUnit4) method of test's base class. - * For JUnit3 initMocks() can go to setup() method of a base class. - * Instead you can also put initMocks() in your JUnit runner (@RunWith) or use the built-in - * {@link MockitoJUnitRunner}. + * MockitoAnnotations.openMocks(this) method has to be called to initialize annotated objects. + * In above example, openMocks() is called in @Before (JUnit4) method of test's base class. + * Instead you can also put openMocks() in your JUnit runner (@RunWith) or use the built-in + * {@link MockitoJUnitRunner}. Also, make sure to release any mocks after disposing your test class with a corresponding hook. *

    * *

    @@ -153,9 +158,14 @@ * be it mocks/spies or real objects. *

    * + *

    + * Elements annotated with this annotation can also be spied upon by also adding the {@link Spy} + * annotation to the element. + *

    + * * @see Mock * @see Spy - * @see MockitoAnnotations#initMocks(Object) + * @see MockitoAnnotations#openMocks(Object) * @see MockitoJUnitRunner * @since 1.8.3 */ diff --git a/mockito-core/src/main/java/org/mockito/Mock.java b/mockito-core/src/main/java/org/mockito/Mock.java new file mode 100644 index 0000000000..4d94edfe26 --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/Mock.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2007 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.plugins.MockMaker; +import org.mockito.stubbing.Answer; + +/** + * Mark a field as a mock. + * + *
      + *
    • Allows shorthand mock creation.
    • + *
    • Minimizes repetitive mock creation code.
    • + *
    • Makes the test class more readable.
    • + *
    • Makes the verification error easier to read because the field name is used to identify the mock.
    • + *
    • Automatically detects static mocks of type {@link MockedStatic} and infers the static mock type of the type parameter.
    • + *
    + * + *
    
    + *   public class ArticleManagerTest extends SampleBaseTestCase {
    + *
    + *       @Mock private ArticleCalculator calculator;
    + *       @Mock(name = "database") private ArticleDatabase dbMock;
    + *       @Mock(answer = RETURNS_MOCKS) private UserProvider userProvider;
    + *       @Mock(extraInterfaces = {Queue.class, Observer.class}) private ArticleMonitor articleMonitor;
    + *       @Mock(strictness = Mock.Strictness.LENIENT) private ArticleConsumer articleConsumer;
    + *       @Mock(stubOnly = true) private Logger logger;
    + *
    + *       private ArticleManager manager;
    + *
    + *       @Before public void setup() {
    + *           manager = new ArticleManager(userProvider, database, calculator, articleMonitor, articleConsumer, logger);
    + *       }
    + *   }
    + *
    + *   public class SampleBaseTestCase {
    + *
    + *       private AutoCloseable closeable;
    + *
    + *       @Before public void openMocks() {
    + *           closeable = MockitoAnnotations.openMocks(this);
    + *       }
    + *
    + *       @After public void releaseMocks() throws Exception {
    + *           closeable.close();
    + *       }
    + *   }
    + * 
    + * + *

    + * MockitoAnnotations.openMocks(this) method has to be called to initialize annotated objects. + * In above example, openMocks() is called in @Before (JUnit4) method of test's base class. + * Instead you can also put openMocks() in your JUnit runner (@RunWith) or use the built-in + * {@link MockitoJUnitRunner}. Also, make sure to release any mocks after disposing your test class with a corresponding hook. + *

    + * + * @see Mockito#mock(Class) + * @see Spy + * @see InjectMocks + * @see MockitoAnnotations#openMocks(Object) + * @see MockitoJUnitRunner + */ +@Target({FIELD, PARAMETER}) +@Retention(RUNTIME) +@Documented +public @interface Mock { + + /** + * Mock will have custom answer, see {@link MockSettings#defaultAnswer(Answer)}. + * For examples how to use 'Mock' annotation and parameters see {@link Mock}. + */ + Answers answer() default Answers.RETURNS_DEFAULTS; + + /** + * Mock will be 'stubOnly', see {@link MockSettings#stubOnly()}. + * For examples how to use 'Mock' annotation and parameters see {@link Mock}. + */ + boolean stubOnly() default false; + + /** + * Mock will have custom name (shown in verification errors), see {@link MockSettings#name(String)}. + * For examples how to use 'Mock' annotation and parameters see {@link Mock}. + */ + String name() default ""; + + /** + * Mock will have extra interfaces, see {@link MockSettings#extraInterfaces(Class[])}. + * For examples how to use 'Mock' annotation and parameters see {@link Mock}. + */ + Class[] extraInterfaces() default {}; + + /** + * Mock will be serializable, see {@link MockSettings#serializable()}. + * For examples how to use 'Mock' annotation and parameters see {@link Mock}. + */ + boolean serializable() default false; + + /** + * @deprecated Use {@link Mock#strictness()} instead. + * + * Mock will be lenient, see {@link MockSettings#lenient()}. + * For examples how to use 'Mock' annotation and parameters see {@link Mock}. + * + * @since 2.23.3 + */ + @Deprecated + boolean lenient() default false; + + /** + * Mock will have custom strictness, see {@link MockSettings#strictness(org.mockito.quality.Strictness)}. + * For examples how to use 'Mock' annotation and parameters see {@link Mock}. + * + * @since 4.6.1 + */ + Strictness strictness() default Strictness.TEST_LEVEL_DEFAULT; + + /** + * Mock will be created by the given {@link MockMaker}, see {@link MockSettings#mockMaker(String)}. + * + * @since 4.8.0 + */ + String mockMaker() default ""; + + /** + * Mock will not attempt to preserve all annotation metadata, see {@link MockSettings#withoutAnnotations()}. + * + * @since 5.3.0 + */ + boolean withoutAnnotations() default false; + + enum Strictness { + + /** + * Default value used to indicate the mock does not override the test level strictness. + * + * @since 4.6.1 + */ + TEST_LEVEL_DEFAULT, + + /** + * See {@link org.mockito.quality.Strictness#LENIENT} + */ + LENIENT, + + /** + * See {@link org.mockito.quality.Strictness#WARN} + */ + WARN, + + /** + * See {@link org.mockito.quality.Strictness#STRICT_STUBS} + */ + STRICT_STUBS + } +} diff --git a/mockito-core/src/main/java/org/mockito/MockMakers.java b/mockito-core/src/main/java/org/mockito/MockMakers.java new file mode 100644 index 0000000000..028a06a922 --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/MockMakers.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import org.mockito.plugins.MockMaker; + +/** + * Constants for built-in implementations of {@code MockMaker}. + * You may use the constants of this class for {@link MockSettings#mockMaker(String)} or {@link Mock#mockMaker()}. + * The string values of these constants may also be used in the resource file mockito-extensions/org.mockito.plugins.MockMaker + * as described in the class documentation of {@link MockMaker}. + * + * @since 4.8.0 + */ +public final class MockMakers { + /** + * Inline mock maker which can mock final types, enums and final methods. + * This mock maker cannot mock native methods, + * and it does not support {@link MockSettings#extraInterfaces(Class[]) extra interfaces}. + * + * @see Mocking final types, enums and final methods + */ + public static final String INLINE = "mock-maker-inline"; + + /** + * Proxy mock maker which avoids code generation, but can only mock interfaces. + * + * @see Avoiding code generation when restricting mocks to interfaces + */ + public static final String PROXY = "mock-maker-proxy"; + + /** + * Subclass mock maker which mocks types by creating subclasses. + * This is the first built-in mock maker which has been provided by Mockito. + * Since this mock maker relies on subclasses, it cannot mock final classes and methods. + */ + public static final String SUBCLASS = "mock-maker-subclass"; + + private MockMakers() {} +} diff --git a/src/main/java/org/mockito/MockSettings.java b/mockito-core/src/main/java/org/mockito/MockSettings.java similarity index 78% rename from src/main/java/org/mockito/MockSettings.java rename to mockito-core/src/main/java/org/mockito/MockSettings.java index 30496d164c..e9c75c3a1e 100644 --- a/src/main/java/org/mockito/MockSettings.java +++ b/mockito-core/src/main/java/org/mockito/MockSettings.java @@ -5,6 +5,7 @@ package org.mockito; import java.io.Serializable; +import java.lang.reflect.Type; import org.mockito.exceptions.misusing.PotentialStubbingProblem; import org.mockito.exceptions.misusing.UnnecessaryStubbingException; @@ -15,6 +16,7 @@ import org.mockito.listeners.VerificationStartedListener; import org.mockito.mock.MockCreationSettings; import org.mockito.mock.SerializableMode; +import org.mockito.plugins.MockMaker; import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; @@ -23,12 +25,12 @@ *

    * Don't use it too often. * Consider writing simple tests that use simple mocks. - * Repeat after me: simple tests push simple, KISSy, readable & maintainable code. + * Repeat after me: simple tests push simple, KISSy, readable and maintainable code. * If you cannot write a test in a simple way - refactor the code under test. *

    * Examples of mock settings: *

    
    - *   //Creates mock with different default answer & name
    + *   //Creates mock with different default answer and name
      *   Foo mock = mock(Foo.class, withSettings()
      *                                .defaultAnswer(RETURNS_SMART_NULLS)
      *                                .name("cool mockie")
    @@ -42,7 +44,7 @@
      * 
    * {@link MockSettings} has been introduced for two reasons. * Firstly, to make it easy to add another mock setting when the demand comes. - * Secondly, to enable combining together different mock settings without introducing zillions of overloaded mock() methods. + * Secondly, to enable combining different mock settings without introducing zillions of overloaded mock() methods. */ @NotExtensible public interface MockSettings extends Serializable { @@ -51,8 +53,8 @@ public interface MockSettings extends Serializable { * Specifies extra interfaces the mock should implement. Might be useful for legacy code or some corner cases. *

    * This mysterious feature should be used very occasionally. - * The object under test should know exactly its collaborators & dependencies. - * If you happen to use it often than please make sure you are really producing simple, clean & readable code. + * The object under test should know exactly its collaborators and dependencies. + * If you happen to use it often than please make sure you are really producing simple, clean and readable code. *

    * Examples: *

    
    @@ -63,7 +65,7 @@ public interface MockSettings extends Serializable {
          *   Baz baz = (Baz) foo;
          * 
    * - * @param interfaces extra interfaces the should implement. + * @param interfaces extra interfaces the mock should implement. * @return settings instance so that you can fluently specify other settings */ MockSettings extraInterfaces(Class... interfaces); @@ -93,7 +95,7 @@ public interface MockSettings extends Serializable { * * Sets the instance that will be spied. Actually copies the internal fields of the passed instance to the mock. *

    - * As usual you are going to read the partial mock warning: + * As usual, you are going to read the partial mock warning: * Object oriented programming is more or less about tackling complexity by dividing the complexity into separate, specific, SRPy objects. * How does partial mock fit into this paradigm? Well, it just doesn't... * Partial mock usually means that the complexity has been moved to a different method on the same object. @@ -101,7 +103,7 @@ public interface MockSettings extends Serializable { *

    * However, there are rare cases when partial mocks come handy: * dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) - * However, I wouldn't use partial mocks for new, test-driven & well-designed code. + * However, I wouldn't use partial mocks for new, test-driven and well-designed code. *

    * Enough warnings about partial mocks, see an example how spiedInstance() works: *

    
    @@ -132,10 +134,10 @@ public interface MockSettings extends Serializable {
     
         /**
          * Specifies default answers to interactions.
    -     * It's quite advanced feature and typically you don't need it to write decent tests.
    -     * However it can be helpful when working with legacy systems.
    +     * It's quite advanced feature, and typically you don't need it to write decent tests.
    +     * However, it can be helpful when working with legacy systems.
          * 

    - * It is the default answer so it will be used only when you don't stub the method call. + * It is the default answer, so it will be used only when you don't stub the method call. * *

    
          *   Foo mock = mock(Foo.class, withSettings().defaultAnswer(RETURNS_SMART_NULLS));
    @@ -208,7 +210,7 @@ public interface MockSettings extends Serializable {
         /**
          * Add stubbing lookup listener to the mock object.
          *
    -     * Multiple listeners may be added and they will be notified orderly.
    +     * Multiple listeners may be added, and they will be notified in an orderly fashion.
          *
          * For use cases and more info see {@link StubbingLookupListener}.
          *
    @@ -227,7 +229,7 @@ public interface MockSettings extends Serializable {
          * Registers a listener for method invocations on this mock. The listener is
          * notified every time a method on this mock is called.
          * 

    - * Multiple listeners may be added and they will be notified in the order they were supplied. + * Multiple listeners may be added, and they will be notified in the order they were supplied. * * Example: *

    
    @@ -246,7 +248,7 @@ public interface MockSettings extends Serializable {
          * See {@link VerificationStartedListener} on how such listener can be useful.
          * 

    * When multiple listeners are added, they are notified in order they were supplied. - * There is no reason to supply multiple listeners but we wanted to keep the API + * There is no reason to supply multiple listeners, but we wanted to keep the API * simple and consistent with {@link #invocationListeners(InvocationListener...)}. *

    * Throws exception when any of the passed listeners is null or when the entire vararg array is null. @@ -255,7 +257,6 @@ public interface MockSettings extends Serializable { * @return settings instance so that you can fluently specify other settings * @since 2.11.0 */ - @Incubating MockSettings verificationStartedListeners(VerificationStartedListener... listeners); /** @@ -296,7 +297,6 @@ public interface MockSettings extends Serializable { * @return settings instance so that you can fluently specify other settings * @since 2.7.14 (useConstructor with no arguments was supported since 1.10.12) */ - @Incubating MockSettings useConstructor(Object... args); /** @@ -311,18 +311,16 @@ public interface MockSettings extends Serializable { * @return settings instance so that you can fluently specify other settings * @since 1.10.12 */ - @Incubating MockSettings outerInstance(Object outerClassInstance); /** - * By default, Mockito makes an attempt to preserve all annotation meta data on the mocked + * By default, Mockito makes an attempt to preserve all annotation metadata on the mocked * type and its methods to mirror the mocked type as closely as possible. If this is not * desired, this option can be used to disable this behavior. * * @return settings instance so that you can fluently specify other settings * @since 1.10.13 */ - @Incubating MockSettings withoutAnnotations(); /** @@ -337,10 +335,25 @@ public interface MockSettings extends Serializable { * @return immutable view of mock settings * @since 2.10.0 */ - @Incubating MockCreationSettings build(Class typeToMock); /** + * Creates immutable view of mock settings used later by Mockito, for use within a static mocking. + * Framework integrators can use this method to create instances of creation settings + * and use them in advanced use cases, for example to create invocations with {@link InvocationFactory}, + * or to implement custom {@link MockHandler}. + * Since {@link MockCreationSettings} is {@link NotExtensible}, Mockito public API needs a creation method for this type. + * + * @param classToMock class to mock + * @param type to mock + * @return immutable view of mock settings + * @since 2.10.0 + */ + MockCreationSettings buildStatic(Class classToMock); + + /** + * @deprecated Use {@link MockSettings#strictness(Strictness)} instead. + * * Lenient mocks bypass "strict stubbing" validation (see {@link Strictness#STRICT_STUBS}). * When mock is declared as lenient none of its stubbings will be checked for potential stubbing problems such as * 'unnecessary stubbing' ({@link UnnecessaryStubbingException}) or for 'stubbing argument mismatch' {@link PotentialStubbingProblem}. @@ -351,6 +364,51 @@ public interface MockSettings extends Serializable { * * For more information and an elaborate example, see {@link Mockito#lenient()}. */ - @Incubating + @Deprecated MockSettings lenient(); + + /** + * Specifies strictness level for the mock. + * The default strictness level is determined by the rule/runner used. + * If you are using no rule/runner, the default strictness level is LENIENT + * + *

    
    +     *   Foo defaultStrictMock = mock(Foo.class);
    +     *   Foo explicitStrictMock = mock(Foo.class, withSettings().strictness(Strictness.STRICT_STUBS));
    +     *   Foo lenientMock = mock(Foo.class, withSettings().strictness(Strictness.LENIENT));
    +     * 
    + * + * @param strictness the strictness level to set on mock + * @return settings instance so that you can fluently specify other settings + * @since 4.6.0 + */ + MockSettings strictness(Strictness strictness); + + /** + * Specifies the {@code MockMaker} for the mock. + * The default depends on your project as described in the class documentation of {@link MockMaker}. + * You should usually use the default, this option primarily exists to ease migrations. + * You may specify either one of the constants from {@link MockMakers}, + *
    +     *     Object mock = Mockito.mock(Object.class, Mockito.withSettings()
    +     *             .mockMaker(MockMakers.INLINE));
    +     * 
    + * or the {@link Class#getName() binary name} of a class which implements the {@code MockMaker} interface. + *
    +     *     Object mock = Mockito.mock(Object.class, Mockito.withSettings()
    +     *             .mockMaker("org.awesome.mockito.AwesomeMockMaker"));
    +     * 
    + * + * @param mockMaker the {@code MockMaker} to use for the mock + * @return settings instance so that you can fluently specify other settings + * @since 4.8.0 + */ + MockSettings mockMaker(String mockMaker); + + /** + * Specifies the generic type of the mock, preserving the information lost to Java type erasure. + * @param genericTypeToMock + * @return + */ + MockSettings genericTypeToMock(Type genericTypeToMock); } diff --git a/mockito-core/src/main/java/org/mockito/MockedConstruction.java b/mockito-core/src/main/java/org/mockito/MockedConstruction.java new file mode 100644 index 0000000000..ccf78c73a2 --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/MockedConstruction.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import java.lang.reflect.Constructor; +import java.util.List; + +/** + * Represents a mock of any object construction of the represented type. Within the scope of the + * mocked construction, the invocation of any interceptor will generate a mock which will be + * prepared as specified when generating this scope. The mock can also be received via this + * instance. + *

    + * If the {@link Mock} annotation is used on fields or method parameters of this type, a mocked + * construction is created instead of a regular mock. The mocked construction is activated and + * released upon completing any relevant test. + * + * @param The type for which the construction is being mocked. + */ +public interface MockedConstruction extends ScopedMock { + + /** + * Get the constructed mocks. + * + * @return the constructed mocks. + */ + List constructed(); + + /** + * The context for a construction mock. + */ + interface Context { + + int getCount(); + + /** + * Get the constructor that is invoked during the mock creation. + * + * @return the constructor. + */ + Constructor constructor(); + + /** + * Get the arguments that were passed to the constructor. + * + * @return the arguments passed to the constructor, as a list. + */ + List arguments(); + } + + /** + * Functional interface that consumes a newly created mock and the mock context. + *

    + * Used to attach behaviours to new mocks. + * + * @param the mock type. + */ + @FunctionalInterface + interface MockInitializer { + + /** + * Configure the mock. + * + * @param mock the newly created mock. + * @param context the mock context. + * @throws Throwable any exception that may be thrown. + */ + void prepare(T mock, Context context) throws Throwable; + } +} diff --git a/mockito-core/src/main/java/org/mockito/MockedStatic.java b/mockito-core/src/main/java/org/mockito/MockedStatic.java new file mode 100644 index 0000000000..113bee2e3a --- /dev/null +++ b/mockito-core/src/main/java/org/mockito/MockedStatic.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2007 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito; + +import static org.mockito.Mockito.times; + +import org.mockito.stubbing.OngoingStubbing; +import org.mockito.verification.VerificationMode; + +/** + * Represents an active mock of a type's static methods. The mocking only affects the thread + * on which this static mock was created and it is not safe to use this object from another + * thread. The static mock is released when this object's {@link MockedStatic#close()} method + * is invoked. If this object is never closed, the static mock will remain active on the + * initiating thread. It is therefore recommended to create this object within a try-with-resources + * statement unless when managed explicitly, for example by using a JUnit rule or extension. + *

    + * If the {@link Mock} annotation is used on fields or method parameters of this type, a static mock + * is created instead of a regular mock. The static mock is activated and released upon completing any + * relevant test. + * + * @param The type being mocked. + */ +public interface MockedStatic extends ScopedMock { + + /** + * See {@link Mockito#when(Object)}. + */ + OngoingStubbing when(Verification verification); + + /** + * See {@link Mockito#verify(Object)}. + */ + default void verify(Verification verification) { + verify(verification, times(1)); + } + + /** + * See {@link Mockito#verify(Object, VerificationMode)}. + */ + void verify(Verification verification, VerificationMode mode); + + /** + * See {@link Mockito#reset(Object[])}. + */ + void reset(); + + /** + * See {@link Mockito#clearInvocations(Object[])}. + */ + void clearInvocations(); + + /** + * {@link Mockito#verifyNoMoreInteractions(Object...)}. + */ + void verifyNoMoreInteractions(); + + /** + * See {@link Mockito#verifyNoInteractions(Object...)}. + */ + void verifyNoInteractions(); + + /** + * Functional interface for a verification operation on a static mock. + */ + @FunctionalInterface + interface Verification { + + /** + * Apply the verification operation. + * + * @throws Throwable any exception that may be thrown. + */ + void apply() throws Throwable; + } +} diff --git a/src/main/java/org/mockito/MockingDetails.java b/mockito-core/src/main/java/org/mockito/MockingDetails.java similarity index 96% rename from src/main/java/org/mockito/MockingDetails.java rename to mockito-core/src/main/java/org/mockito/MockingDetails.java index be7dc6352a..37a149100a 100644 --- a/src/main/java/org/mockito/MockingDetails.java +++ b/mockito-core/src/main/java/org/mockito/MockingDetails.java @@ -73,7 +73,7 @@ public interface MockingDetails { * What is 'stubbing'? * Stubbing is your when(x).then(y) declaration, e.g. configuring the mock to behave in a specific way, * when specific method with specific arguments is invoked on a mock. - * Typically stubbing is configuring mock to return X when method Y is invoked. + * Typically, stubbing is configuring mock to return X when method Y is invoked. *

    * Why do you need to access stubbings of a mock? * In a normal workflow of creation clean tests, there is no need for this API. @@ -102,8 +102,6 @@ public interface MockingDetails { * Don't write code that depends on the output of this method. * If you need to know about interactions and stubbings, use {@link #getStubbings()} and {@link #getInvocations()}. *

    - * This method was moved from the deprecated and semi-hidden type {@link MockitoDebugger}. - *

    * This method throws meaningful exception when object wrapped by MockingDetails is not a mock. * * @since 2.2.6 @@ -119,7 +117,6 @@ public interface MockingDetails { * @return mock handler instance of this mock * @since 2.10.0 */ - @Incubating MockHandler getMockHandler(); /** diff --git a/src/main/java/org/mockito/Mockito.java b/mockito-core/src/main/java/org/mockito/Mockito.java similarity index 77% rename from src/main/java/org/mockito/Mockito.java rename to mockito-core/src/main/java/org/mockito/Mockito.java index af1ceb22e9..452f8ee44e 100644 --- a/src/main/java/org/mockito/Mockito.java +++ b/mockito-core/src/main/java/org/mockito/Mockito.java @@ -6,18 +6,18 @@ import org.mockito.exceptions.misusing.PotentialStubbingProblem; import org.mockito.exceptions.misusing.UnnecessaryStubbingException; -import org.mockito.internal.InternalMockHandler; import org.mockito.internal.MockitoCore; import org.mockito.internal.creation.MockSettingsImpl; -import org.mockito.internal.debugging.MockitoDebuggerImpl; import org.mockito.internal.framework.DefaultMockitoFramework; import org.mockito.internal.session.DefaultMockitoSessionBuilder; +import org.mockito.internal.util.MockUtil; import org.mockito.internal.verification.VerificationModeFactory; import org.mockito.invocation.Invocation; import org.mockito.invocation.InvocationFactory; import org.mockito.invocation.MockHandler; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner.Strict; import org.mockito.junit.MockitoRule; import org.mockito.listeners.VerificationStartedEvent; import org.mockito.listeners.VerificationStartedListener; @@ -33,7 +33,6 @@ import org.mockito.stubbing.LenientStubber; import org.mockito.stubbing.OngoingStubbing; import org.mockito.stubbing.Stubber; -import org.mockito.stubbing.Stubbing; import org.mockito.stubbing.VoidAnswer1; import org.mockito.verification.After; import org.mockito.verification.Timeout; @@ -41,12 +40,15 @@ import org.mockito.verification.VerificationMode; import org.mockito.verification.VerificationWithTimeout; +import java.util.function.Consumer; +import java.util.function.Function; + /** *

    Mockito logo

    * The Mockito library enables mock creation, verification and stubbing. * *

    - * This javadoc content is also available on the http://mockito.org web page. + * This javadoc content is also available on the https://site.mockito.org/ web page. * All documentation is kept in javadocs because it guarantees consistency between what's on the web and what's in the source code. * It allows access to documentation straight from the IDE even if you work offline. * It motivates Mockito developers to keep documentation up-to-date with the code that they write, @@ -56,8 +58,9 @@ * * * 0. Migrating to Mockito 2
    - * 0.1 Mockito Android support
    - * 0.2 Configuration-free inline mock making
    + * 0.1 Mockito Android support
    + * 0.2 Configuration-free inline mock making
    + * 0.3 Explicitly enabling instrumentation for inline mocking (Java 21+)
    * 1. Let's verify some behaviour!
    * 2. How about some stubbing?
    * 3. Argument matchers
    @@ -71,11 +74,11 @@ * 11. Stubbing with callbacks
    * 12. doReturn()|doThrow()|doAnswer()|doNothing()|doCallRealMethod() family of methods
    * 13. Spying on real objects
    - * 14. Changing default return values of unstubbed invocations (Since 1.7)
    + * 14. Changing default return values of un-stubbed invocations (Since 1.7)
    * 15. Capturing arguments for further assertions (Since 1.8.0)
    * 16. Real partial mocks (Since 1.8.0)
    * 17. Resetting mocks (Since 1.8.0)
    - * 18. Troubleshooting & validating framework usage (Since 1.8.0)
    + * 18. Troubleshooting and validating framework usage (Since 1.8.0)
    * 19. Aliases for behavior driven development (Since 1.8.0)
    * 20. Serializable mocks (Since 1.8.1)
    * 21. New annotations: @Captor, @Spy, @InjectMocks (Since 1.8.3)
    @@ -105,12 +108,19 @@ * 45. New JUnit Jupiter (JUnit5+) extension
    * 46. New Mockito.lenient() and MockSettings.lenient() methods (Since 2.20.0)
    * 47. New API for clearing mock state in inline mocking (Since 2.25.0)
    + * 48. New API for mocking static methods (Since 3.4.0)
    + * 49. New API for mocking object construction (Since 3.5.0)
    + * 50. Avoiding code generation when restricting mocks to interfaces (Since 3.12.2)
    + * 51. New API for marking classes as unmockable (Since 4.1.0)
    + * 52. New strictness attribute for @Mock annotation and MockSettings.strictness() methods (Since 4.6.0)
    + * 53. Specifying mock maker for individual mocks (Since 4.8.0)
    + * 54. Mocking/spying without specifying class (Since 4.10.0)
    *
    * *

    0. Migrating to Mockito 2

    * * In order to continue improving Mockito and further improve the unit testing experience, we want you to upgrade to 2.1.0! - * Mockito follows semantic versioning and contains breaking changes only on major version upgrades. + * Mockito follows semantic versioning and contains breaking changes only on major version upgrades. * In the lifecycle of a library, breaking changes are necessary * to roll out a set of brand new features that alter the existing behavior or even change the API. * For a comprehensive guide on the new release including incompatible changes, @@ -124,7 +134,7 @@ * *
    
      * repositories {
    - *   jcenter()
    + *   mavenCentral()
      * }
      * dependencies {
      *   testCompile "org.mockito:mockito-core:+"
    @@ -146,18 +156,112 @@
      *
      * 
    
      * repositories {
    - *   jcenter()
    + *   mavenCentral()
      * }
      * dependencies {
      *   testCompile "org.mockito:mockito-inline:+"
      * }
      * 
    * - * Be aware that this artifact may be abolished when the inline mock making feature is integrated into the default mock maker. + * Be aware that starting from 5.0.0 the inline mock maker became the default mock maker and this + * artifact may be abolished in future versions. * *

    * For more information about inline mock making, see section 39. * + *

    0.3. Explicitly setting up instrumentation for inline mocking (Java 21+)

    + * + * Starting from Java 21, the JDK restricts the ability of libraries + * to attach a Java agent to their own JVM. As a result, the inline-mock-maker might not be able + * to function without an explicit setup to enable instrumentation, and the JVM will always display a warning. + * + * The following are examples about how to set up mockito-core as a Java agent, and it may be more appropriate to choose + * a different approach depending on your project constraints. + * + *

    + * To explicitly attach Mockito during test execution, the library's jar file needs to be specified as -javaagent + * as an argument to the executing JVM. To enable this in Gradle, the following example adds Mockito to all test + * tasks using Kotlin DSL. Although omitted for simplicity, using a CommandLineArgumentProvider is recommended by Gradle to ensure task relocatability (documentation): + * + *

    
    + * val mockitoAgent = configurations.create("mockitoAgent")
    + * dependencies {
    + *     testImplementation(libs.mockito)
    + *     mockitoAgent(libs.mockito) { isTransitive = false }
    + * }
    + * tasks {
    + *     test {
    + *         jvmArgs.add("-javaagent:${mockitoAgent.asPath}")
    + *     }
    + * }
    + * 
    + * + * The same can be achieved using Groovy DSL: + * + *
    
    + * configurations {
    + *     mockitoAgent
    + * }
    + * dependencies {
    + *     testImplementation(libs.mockito)
    + *     mockitoAgent(libs.mockito) {
    + *         transitive = false
    + *     }
    + * }
    + * tasks {
    + *     test {
    + *         jvmArgs += "-javaagent:${configurations.mockitoAgent.asPath}"
    + *     }
    + * }
    + * 
    + * + * Supposing Mockito is declared in the version catalog as the following + * + *
    
    + * [versions]
    + * mockito = "5.14.0"
    + *
    + * [libraries]
    + * mockito = { module = "org.mockito:mockito-core", version.ref = "mockito" }
    + * 
    + * + * To add Mockito as an agent to Maven's surefire plugin, the following configuration is needed: + * + *
    
    + * <plugin>
    + *     <groupId>org.apache.maven.plugins</groupId>
    + *     <artifactId>maven-dependency-plugin</artifactId>
    + *     <executions>
    + *         <execution>
    + *             <goals>
    + *                 <goal>properties</goal>
    + *             </goals>
    + *         </execution>
    + *     </executions>
    + * </plugin>
    + * <plugin>
    + *     <groupId>org.apache.maven.plugins</groupId>
    + *     <artifactId>maven-surefire-plugin</artifactId>
    + *     <configuration>
    + *         <argLine>@{argLine} -javaagent:${org.mockito:mockito-core:jar}</argLine>
    + *     </configuration>
    + * </plugin>
    + * 
    + * + *
    + * Note however, that @{argLine} needs to exist when surefire performs its + * late replacement otherwise + * it will just use the value verbatim which will crash the VM, + * The forked VM terminated without properly saying goodbye. VM crash or System.exit called., in this case, + * you may need to adapt your maven configuration, for example by adding an empty <argLine/> property + * to the POM file. + *
    + * + *

    + * Alternatively, to enable support for dynamic attach, it is also possible to start a JVM with + * -XX:+EnableDynamicAgentLoading flag. Do however note that, since this option is not standardized, any future + * release of a JDK might prohibit this behaviour. + * *

    1. Let's verify some behaviour!

    * * The following examples mock a List, because most people are familiar with the interface (such as the @@ -219,7 +323,7 @@ * *
  3. Stubbing can be overridden: for example common stubbing can go to * fixture setup but the test methods can override it. - * Please note that overridding stubbing is a potential code smell that points out too much stubbing
  4. + * Please note that overriding stubbing is a potential code smell that points out too much stubbing * *
  5. Once stubbed, the method will always return a stubbed value, regardless * of how many times it is called.
  6. @@ -252,7 +356,7 @@ * verify(mockedList).get(anyInt()); * * //argument matchers can also be written as Java 8 Lambdas - * verify(mockedList).add(argThat(someString -> someString.length() > 5)); + * verify(mockedList).add(argThat(someString -> someString.length() > 5)); * *
    * @@ -264,7 +368,7 @@ * For information solely on custom argument matchers check out javadoc for {@link ArgumentMatcher} class. *

    * Be reasonable with using complicated argument matching. - * The natural matching style using equals() with occasional anyX() matchers tend to give clean & simple tests. + * The natural matching style using equals() with occasional anyX() matchers tend to give clean and simple tests. * Sometimes it's just better to refactor the code to allow equals() matching or even implement equals() method to help out with testing. *

    * Also, read section 15 or javadoc for {@link ArgumentCaptor} class. @@ -275,7 +379,7 @@ * If you are using argument matchers, all arguments have to be provided * by matchers. *

    - The following example shows verification but the same applies to stubbing: + * The following example shows verification but the same applies to stubbing: * *

    
      *   verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
    @@ -286,10 +390,10 @@
      * 
    * *

    - * Matcher methods like anyObject(), eq() do not return matchers. + * Matcher methods like any(), eq() do not return matchers. * Internally, they record a matcher on a stack and return a dummy value (usually null). * This implementation is due to static type safety imposed by the java compiler. - * The consequence is that you cannot use anyObject(), eq() methods outside of verified/stubbed method. + * The consequence is that you cannot use any(), eq() methods outside of verified/stubbed method. * * * @@ -403,9 +507,6 @@ * //verify that method was never called on a mock * verify(mockOne, never()).add("two"); * - * //verify that other mocks were not interacted - * verifyZeroInteractions(mockTwo, mockThree); - * *

    * * @@ -455,13 +556,16 @@ * @Mock private UserProvider userProvider; * * private ArticleManager manager; + * + * @org.junit.jupiter.api.Test + * void testSomethingInJunit5(@Mock ArticleDatabase database) { *
    * * Important! This needs to be somewhere in the base class or a test * runner: * *
    
    - * MockitoAnnotations.initMocks(testClass);
    + * MockitoAnnotations.openMocks(testClass);
      * 
    * * You can use built-in runner: {@link MockitoJUnitRunner} or a rule: {@link MockitoRule}. @@ -525,7 +629,7 @@ * Yet another controversial feature which was not included in Mockito * originally. We recommend simply stubbing with thenReturn() or * thenThrow(), which should be enough to test/test-drive - * any clean & simple code. However, if you do have a need to stub with the generic Answer interface, here is an example: + * any clean and simple code. However, if you do have a need to stub with the generic Answer interface, here is an example: * *
    
      * when(mock.someMethod(anyString())).thenAnswer(
    @@ -645,7 +749,7 @@
      * 
  7. Mockito *does not* delegate calls to the passed real instance, instead it actually creates a copy of it. * So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction * and their effect on real instance state. - * The corollary is that when an *unstubbed* method is called *on the spy* but *not on the real instance*, + * The corollary is that when an *un-stubbed* method is called *on the spy* but *not on the real instance*, * you won't see any effects on the real instance. *
  8. * @@ -658,7 +762,7 @@ * * * - *

    14. Changing default return values of unstubbed invocations (Since 1.7)

    + *

    14. Changing default return values of un-stubbed invocations (Since 1.7)

    * * You can create a mock with specified strategy for its return values. * It's quite an advanced feature and typically you don't need it to write decent tests. @@ -680,7 +784,7 @@ *

    15. Capturing arguments for further assertions (Since 1.8.0)

    * * Mockito verifies argument values in natural java style: by using an equals() method. - * This is also the recommended way of matching arguments because it makes tests clean & simple. + * This is also the recommended way of matching arguments because it makes tests clean and simple. * In some situations though, it is helpful to assert on certain arguments after the actual verification. * For example: *
    
    @@ -707,7 +811,7 @@
      *
      * 

    16. Real partial mocks (Since 1.8.0)

    * - * Finally, after many internal debates & discussions on the mailing list, partial mock support was added to Mockito. + * Finally, after many internal debates and discussions on the mailing list, partial mock support was added to Mockito. * Previously we considered partial mocks as code smells. However, we found a legitimate use case for partial mocks. *

    * Before release 1.8 spy() was not producing real partial mocks and it was confusing for some users. @@ -732,19 +836,19 @@ *

    * However, there are rare cases when partial mocks come handy: * dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) - * However, I wouldn't use partial mocks for new, test-driven & well-designed code. + * However, I wouldn't use partial mocks for new, test-driven and well-designed code. * * * * *

    17. Resetting mocks (Since 1.8.0)

    * - * Smart Mockito users hardly use this feature because they know it could be a sign of poor tests. + * Using this method could be an indication of poor testing. * Normally, you don't need to reset your mocks, just create new mocks for each test method. *

    * Instead of reset() please consider writing simple, small and focused test methods over lengthy, over-specified tests. * First potential code smell is reset() in the middle of the test method. This probably means you're testing too much. - * Follow the whisper of your test methods: "Please keep us small & focused on single behavior". + * Follow the whisper of your test methods: "Please keep us small and focused on single behavior". * There are several threads about it on mockito mailing list. *

    * The only reason we added reset() method is to @@ -758,19 +862,19 @@ * mock.add(1); * * reset(mock); - * //at this point the mock forgot any interactions & stubbing + * //at this point the mock forgot any interactions and stubbing *

    * * * * - *

    18. Troubleshooting & validating framework usage (Since 1.8.0)

    + *

    18. Troubleshooting and validating framework usage (Since 1.8.0)

    * * First of all, in case of any trouble, I encourage you to read the Mockito FAQ: * https://github.com/mockito/mockito/wiki/FAQ *

    * In case of questions you may also post to mockito mailing list: - * http://groups.google.com/group/mockito + * https://groups.google.com/group/mockito *

    * Next, you should know that Mockito validates if you use it correctly all the time. * However, there's a gotcha so please read the javadoc for {@link Mockito#validateMockitoUsage()} @@ -783,7 +887,7 @@ * Behavior Driven Development style of writing tests uses //given //when //then comments as fundamental parts of your test methods. * This is exactly how we write our tests and we warmly encourage you to do so! *

    - * Start learning about BDD here: http://en.wikipedia.org/wiki/Behavior_Driven_Development + * Start learning about BDD here: https://en.wikipedia.org/wiki/Behavior-driven_development *

    * The problem is that current stubbing api with canonical role of when word does not integrate nicely with //given //when //then comments. * It's because stubbing belongs to given component of the test and not to the when component of the test. @@ -826,7 +930,7 @@ * List serializableMock = mock(List.class, withSettings().serializable()); *

    *

    - * The mock can be serialized assuming all the normal + * The mock can be serialized assuming all the normal * serialization requirements are met by the class. *

    * Making a real object spy serializable is a bit more effort as the spy(...) method does not have an overloaded version @@ -863,7 +967,7 @@ * should only use partial mocks as a last resort. See point 16 about partial mocks. * *

    - * All new annotations are *only* processed on {@link MockitoAnnotations#initMocks(Object)}. + * All new annotations are *only* processed on {@link MockitoAnnotations#openMocks(Object)}. * Just like for @{@link Mock} annotation you can use the built-in runner: {@link MockitoJUnitRunner} or rule: * {@link MockitoRule}. *

    @@ -907,7 +1011,7 @@ * Mockito will now try to instantiate @{@link Spy} and will instantiate @{@link InjectMocks} fields * using constructor injection, setter injection, or field injection. *

    - * To take advantage of this feature you need to use {@link MockitoAnnotations#initMocks(Object)}, {@link MockitoJUnitRunner} + * To take advantage of this feature you need to use {@link MockitoAnnotations#openMocks(Object)}, {@link MockitoJUnitRunner} * or {@link MockitoRule}. *

    * Read more about available tricks and the rules of injection in the javadoc for {@link InjectMocks} @@ -929,7 +1033,7 @@ * Mockito will now allow you to create mocks when stubbing. * Basically, it allows to create a stub in one line of code. * This can be helpful to keep test code clean. - * For example, some boring stub can be created & stubbed at field initialization in a test: + * For example, some boring stub can be created and stubbed at field initialization in a test: *

    
      * public class CarTest {
      *   Car boringStubbedCar = when(mock(Car.class).shiftGear()).thenThrow(EngineNotStarted.class).getMock();
    @@ -1076,7 +1180,7 @@
      * SomeAbstract spy = spy(SomeAbstract.class);
      *
      * //Mocking abstract methods, spying default methods of an interface (only available since 2.7.13)
    - * Function function = spy(Function.class);
    + * Function<Foo, Bar> function = spy(Function.class);
      *
      * //Robust API, via settings builder:
      * OtherAbstract spy = mock(OtherAbstract.class, withSettings()
    @@ -1100,7 +1204,7 @@
      *
      * Mockito introduces serialization across classloader.
      *
    - * Like with any other form of serialization, all types in the mock hierarchy have to serializable, inclusing answers.
    + * Like with any other form of serialization, all types in the mock hierarchy have to serializable, including answers.
      * As this serialization mode require considerably more work, this is an opt-in setting.
      *
      * 
    
    @@ -1144,7 +1248,7 @@
      *
      * 
      *
    • Annotating the JUnit test class with a @{@link org.junit.runner.RunWith}({@link MockitoJUnitRunner}.class)
    • - *
    • Invoking {@link MockitoAnnotations#initMocks(Object)} in the @{@link org.junit.Before} method
    • + *
    • Invoking {@link MockitoAnnotations#openMocks(Object)} in the @{@link org.junit.Before} method
    • *
    * * Now you can choose to use a rule : @@ -1200,21 +1304,21 @@ * * // verify a list only had strings of a certain length added to it * // note - this will only compile under Java 8 - * verify(list, times(2)).add(argThat(string -> string.length() < 5)); + * verify(list, times(2)).add(argThat(string -> string.length() < 5)); * * // Java 7 equivalent - not as neat - * verify(list, times(2)).add(argThat(new ArgumentMatcher(){ + * verify(list, times(2)).add(argThat(new ArgumentMatcher<String>(){ * public boolean matches(String arg) { - * return arg.length() < 5; + * return arg.length() < 5; * } * })); * * // more complex Java 8 example - where you can specify complex verification behaviour functionally - * verify(target, times(1)).receiveComplexObject(argThat(obj -> obj.getSubObject().get(0).equals("expected"))); + * verify(target, times(1)).receiveComplexObject(argThat(obj -> obj.getSubObject().get(0).equals("expected"))); * * // this can also be used when defining the behaviour of a mock under different inputs * // in this case if the input list was fewer than 3 items the mock returns null - * when(mock.someMethod(argThat(list -> list.size()<3))).thenReturn(null); + * when(mock.someMethod(argThat(list -> list.size()<3))).thenReturn(null); *
    * *

    37. Java 8 Custom Answer Support (Since 2.1.0)

    @@ -1228,12 +1332,12 @@ *

    *

    
      * // answer by returning 12 every time
    - * doAnswer(invocation -> 12).when(mock).doSomething();
    + * doAnswer(invocation -> 12).when(mock).doSomething();
      *
      * // answer by using one of the parameters - converting into the right
      * // type as your go - in this case, returning the length of the second string parameter
      * // as the answer. This gets long-winded quickly, with casting of parameters.
    - * doAnswer(invocation -> ((String)invocation.getArgument(1)).length())
    + * doAnswer(invocation -> ((String)invocation.getArgument(1)).length())
      *     .when(mock).doSomething(anyString(), anyString(), anyString());
      * 
    * @@ -1241,8 +1345,8 @@ * as Java 8 lambdas. Even in Java 7 and lower these custom answers based on a typed interface can reduce boilerplate. * In particular, this approach will make it easier to test functions which use callbacks. * - * The methods {@link AdditionalAnswers#answer(Answer1) answer} and {@link AdditionalAnswers#answerVoid(VoidAnswer1) answerVoid} - * can be used to create the answer. They rely on the related answer interfaces in {@link org.mockito.stubbing} that + * The methods {@link AdditionalAnswers#answer(Answer1)}} and {@link AdditionalAnswers#answerVoid(VoidAnswer1)} + * can be used to create the answer. They rely on the related answer interfaces in org.mockito.stubbing that * support answers up to 5 parameters. * *

    @@ -1258,11 +1362,11 @@ * void receive(String item); * * // Java 8 - style 1 - * doAnswer(AdditionalAnswers.answerVoid((operand, callback) -> callback.receive("dummy")) + * doAnswer(AdditionalAnswers.<String,Callback>answerVoid((operand, callback) -> callback.receive("dummy"))) * .when(mock).execute(anyString(), any(Callback.class)); * * // Java 8 - style 2 - assuming static import of AdditionalAnswers - * doAnswer(answerVoid((String operand, Callback callback) -> callback.receive("dummy")) + * doAnswer(answerVoid((String operand, Callback callback) -> callback.receive("dummy"))) * .when(mock).execute(anyString(), any(Callback.class)); * * // Java 8 - style 3 - where mocking function to is a static member of test class @@ -1270,11 +1374,11 @@ * callback.receive("dummy"); * } * - * doAnswer(answerVoid(TestClass::dummyCallbackImpl) + * doAnswer(answerVoid(TestClass::dummyCallbackImpl)) * .when(mock).execute(anyString(), any(Callback.class)); * * // Java 7 - * doAnswer(answerVoid(new VoidAnswer2() { + * doAnswer(answerVoid(new VoidAnswer2<String, Callback>() { * public void answer(String operation, Callback callback) { * callback.receive("dummy"); * }})).when(mock).execute(anyString(), any(Callback.class)); @@ -1286,11 +1390,11 @@ * * // this could be mocked * // Java 8 - * doAnswer(AdditionalAnswers.answer((input1, input2) -> input1.equals(input2)))) + * doAnswer(AdditionalAnswers.<Boolean,String,String>answer((input1, input2) -> input1.equals(input2))) * .when(mock).execute(anyString(), anyString()); * * // Java 7 - * doAnswer(answer(new Answer2() { + * doAnswer(answer(new Answer2<String, String, String>() { * public String answer(String input1, String input2) { * return input1 + input2; * }})).when(mock).execute(anyString(), anyString()); @@ -1320,12 +1424,11 @@ * *

    39. Mocking final types, enums and final methods (Since 2.1.0)

    * - * Mockito now offers an {@link Incubating}, optional support for mocking final classes and methods. + * Mockito now offers support for mocking final classes and methods by default. * This is a fantastic improvement that demonstrates Mockito's everlasting quest for improving testing experience. * Our ambition is that Mockito "just works" with final classes and methods. * Previously they were considered unmockable, preventing the user from mocking. - * We already started discussing how to make this feature enabled by default. - * Currently, the feature is still optional as we wait for more feedback from the community. + * Since 5.0.0, this feature is enabled by default. * *

    * This alternative mock maker which uses @@ -1333,10 +1436,10 @@ * a mock. This way, it becomes possible to mock final types and methods. * *

    - * This mock maker is turned off by default because it is based on completely different mocking mechanism - * that requires more feedback from the community. It can be activated explicitly by the mockito extension mechanism, - * just create in the classpath a file /mockito-extensions/org.mockito.plugins.MockMaker - * containing the value mock-maker-inline. + * In versions preceding 5.0.0, this mock maker is turned off by default because it is based on + * completely different mocking mechanism that required more feedback from the community. It can be activated + * explicitly by the mockito extension mechanism, just create in the classpath a file + * /mockito-extensions/org.mockito.plugins.MockMaker containing the value mock-maker-inline. * *

    * As a convenience, the Mockito team provides an artifact where this mock maker is preconfigured. Instead of using the @@ -1360,7 +1463,7 @@ * *

  9. This mock maker has been designed around Java Agent runtime attachment ; this require a compatible JVM, * that is part of the JDK (or Java 9 VM). When running on a non-JDK VM prior to Java 9, it is however possible to - * manually add the Byte Buddy Java agent jar using the -javaagent + * manually add the Byte Buddy Java agent jar using the -javaagent * parameter upon starting the JVM. *
  10. * @@ -1374,9 +1477,11 @@ * * To quickly find out how "stricter" Mockito can make you more productive and get your tests cleaner, see: *
      - *
    • Strict stubbing with JUnit Rules - {@link MockitoRule#strictness(Strictness)} with {@link Strictness#STRICT_STUBS}
    • - *
    • Strict stubbing with JUnit Runner - {@link MockitoJUnitRunner.StrictStubs}
    • - *
    • Strict stubbing if you cannot use runner/rule (like TestNG) - {@link MockitoSession}
    • + *
    • Strict stubbing with JUnit4 Rules - {@link MockitoRule#strictness(Strictness)} with {@link Strictness#STRICT_STUBS}
    • + *
    • Strict stubbing with JUnit4 Runner - {@link Strict MockitoJUnitRunner.Strict}
    • + *
    • Strict stubbing with JUnit5 Extension - org.mockito.junit.jupiter.MockitoExtension
    • + *
    • Strict stubbing with TestNG Listener MockitoTestNGListener
    • + *
    • Strict stubbing if you cannot use runner/rule - {@link MockitoSession}
    • *
    • Unnecessary stubbing detection with {@link MockitoJUnitRunner}
    • *
    • Stubbing argument mismatch warnings, documented in {@link MockitoHint}
    • *
    @@ -1433,16 +1538,11 @@ * Provides access to invocation container object which has no methods (marker interface). * Container is needed to hide the internal implementation and avoid leaking it to the public API. * - *
  11. Changed {@link Stubbing} - + *
  12. Changed {@link org.mockito.stubbing.Stubbing} - * it now extends {@link Answer} interface. * It is backwards compatible because Stubbing interface is not extensible (see {@link NotExtensible}). * The change should be seamless to our users. *
  13. - *
  14. Deprecated {@link InternalMockHandler} - - * In order to accommodate API changes we needed to deprecate this interface. - * The interface was always documented as internal, we don't have evidence it was used by the community. - * The deprecation should be completely seamless for our users. - *
  15. *
  16. {@link NotExtensible} - * Public annotation that indicates to the user that she should not provide custom implementations of given type. * Helps framework integrators and our users understand how to use Mockito API safely. @@ -1502,14 +1602,14 @@ * Deprecated org.mockito.plugins.InstantiatorProvider as it was leaking internal API. it was * replaced by org.mockito.plugins.InstantiatorProvider2 (Since 2.15.4) * - *

    {@link org.mockito.plugins.InstantiatorProvider} returned an internal API. Hence it was deprecated and replaced - * by {@link org.mockito.plugins.InstantiatorProvider2}. Old {@link org.mockito.plugins.InstantiatorProvider - * instantiator providers} will continue to work, but it is recommended to switch to the new API.

    + *

    org.mockito.plugins.InstantiatorProvider returned an internal API. Hence it was deprecated and replaced + * by {@link org.mockito.plugins.InstantiatorProvider2}. org.mockito.plugins.InstantiatorProvider + * has now been removed.

    * *

    45. New JUnit Jupiter (JUnit5+) extension

    * * For integration with JUnit Jupiter (JUnit5+), use the `org.mockito:mockito-junit-jupiter` artifact. - * For more information about the usage of the integration, see the JavaDoc of MockitoExtension. + * For more information about the usage of the integration, see the JavaDoc of MockitoExtension. * *

    46. * New Mockito.lenient() and MockSettings.lenient() methods (Since 2.20.0)

    @@ -1541,7 +1641,136 @@ * Hence, we introduced a new API to explicitly clear mock state (only make sense in inline mocking!). * See example usage in {@link MockitoFramework#clearInlineMocks()}. * If you have feedback or a better idea how to solve the problem please reach out. + * + * + *

    48. Mocking static methods (since 3.4.0)

    + * + * When using the inline mock maker, it is possible to mock static method invocations within the current + * thread and a user-defined scope. This way, Mockito assures that concurrently and sequentially running tests do not interfere. + * + * To make sure a static mock remains temporary, it is recommended to define the scope within a try-with-resources construct. + * In the following example, the Foo type's static method would return foo unless mocked: + * + *
    
    + * assertEquals("foo", Foo.method());
    + * try (MockedStatic mocked = mockStatic(Foo.class)) {
    + * mocked.when(Foo::method).thenReturn("bar");
    + * assertEquals("bar", Foo.method());
    + * mocked.verify(Foo::method);
    + * }
    + * assertEquals("foo", Foo.method());
    + * 
    + * + * Due to the defined scope of the static mock, it returns to its original behavior once the scope is released. To define mock + * behavior and to verify static method invocations, use the MockedStatic that is returned. + *

    + * + *

    49. Mocking object construction (since 3.5.0)

    + * + * When using the inline mock maker, it is possible to generate mocks on constructor invocations within the current + * thread and a user-defined scope. This way, Mockito assures that concurrently and sequentially running tests do not interfere. + * + * To make sure a constructor mocks remain temporary, it is recommended to define the scope within a try-with-resources construct. + * In the following example, the Foo type's construction would generate a mock: + * + *
    
    + * assertEquals("foo", new Foo().method());
    + * try (MockedConstruction mocked = mockConstruction(Foo.class)) {
    + * Foo foo = new Foo();
    + * when(foo.method()).thenReturn("bar");
    + * assertEquals("bar", foo.method());
    + * verify(foo).method();
    + * }
    + * assertEquals("foo", new Foo().method());
    + * 
    + * + * Due to the defined scope of the mocked construction, object construction returns to its original behavior once the scope is + * released. To define mock behavior and to verify method invocations, use the MockedConstruction that is returned. + *

    + * + *

    50. Avoiding code generation when only interfaces are mocked (since 3.12.2)

    + * + * The JVM offers the {@link java.lang.reflect.Proxy} facility for creating dynamic proxies of interface types. For most applications, Mockito + * must be capable of mocking classes as supported by the default mock maker, or even final classes, as supported by the inline mock maker. To + * create such mocks, Mockito requires to setup diverse JVM facilities and must apply code generation. If only interfaces are supposed to be + * mocked, one can however choose to use a org.mockito.internal.creation.proxy.ProxyMockMaker that is based on the {@link java.lang.reflect.Proxy} + * API which avoids diverse overhead of the other mock makers but also limits mocking to interfaces. + * + * This mock maker can be activated explicitly by the mockito extension mechanism, just create in the classpath a file + * /mockito-extensions/org.mockito.plugins.MockMaker containing the value mock-maker-proxy. + * + *

    51. Mark classes as unmockable (since 4.1.0)

    + * + * In some cases, mocking a class/interface can lead to unexpected runtime behavior. For example, mocking a java.util.List + * is difficult, given the requirements imposed by the interface. This means that on runtime, depending on what methods the application + * calls on the list, your mock might behave in such a way that it violates the interface. + * + *

    + * For any class/interface you own that is problematic to mock, you can now mark the class with {@link org.mockito.DoNotMock @DoNotMock}. For usage + * of the annotation and how to ship your own (to avoid a compile time dependency on a test artifact), please see its JavaDoc. + *

    + * + *

    52. + * New strictness attribute for @Mock annotation and MockSettings.strictness() methods (Since 4.6.0)

    + * + * You can now customize the strictness level for a single mock, either using `@Mock` annotation strictness attribute or + * using `MockSettings.strictness()`. This can be useful if you want all of your mocks to be strict, + * but one of the mocks to be lenient. + * + *
    
    + *   @Mock(strictness = Strictness.LENIENT)
    + *   Foo mock;
    + *   // using MockSettings.withSettings()
    + *   Foo mock = Mockito.mock(Foo.class, withSettings().strictness(Strictness.WARN));
    + * 
    + * + *

    53. + * Specifying mock maker for individual mocks (Since 4.8.0)

    + * + * You may encounter situations where you want to use a different mock maker for a specific test only. + * In such case, you can (temporarily) use {@link MockSettings#mockMaker(String)} and {@link Mock#mockMaker()} + * to specify the mock maker for a specific mock which is causing the problem. + * + *
    
    + *   // using annotation
    + *   @Mock(mockMaker = MockMakers.SUBCLASS)
    + *   Foo mock;
    + *   // using MockSettings.withSettings()
    + *   Foo mock = Mockito.mock(Foo.class, withSettings().mockMaker(MockMakers.SUBCLASS));
    + * 
    + * + *

    54. + * Mocking/spying without specifying class (Since 4.10.0)

    + * + * Instead of calling method {@link Mockito#mock(Class)} or {@link Mockito#spy(Class)} with Class parameter, you can + * now call method {@code mock()} or {@code spy()} without parameters: + * + *
    
    + *   Foo foo = Mockito.mock();
    + *   Bar bar = Mockito.spy();
    + * 
    + * + * Mockito will automatically detect the needed class. + *

    + * It works only if you assign result of {@code mock()} or {@code spy()} to a variable or field with an explicit type. + * With an implicit type, the Java compiler is unable to automatically determine the type of a mock and you need + * to pass in the {@code Class} explicitly. + *

    + * + *

    55. + * Verification with assertions (Since 5.3.0)

    + * + * To validate arguments during verification, instead of capturing them with {@link ArgumentCaptor}, you can now + * use {@link ArgumentMatchers#assertArg(Consumer)}}: + * + *
    
    + *   verify(serviceMock).doStuff(assertArg(param -> {
    + *     assertThat(param.getField1()).isEqualTo("foo");
    + *     assertThat(param.getField2()).isEqualTo("bar");
    + *   }));
    + * 
    */ +@CheckReturnValue @SuppressWarnings("unchecked") public class Mockito extends ArgumentMatchers { @@ -1550,9 +1779,9 @@ public class Mockito extends ArgumentMatchers { /** * The default Answer of every mock if the mock was not stubbed. * - * Typically it just returns some empty value. + * Typically, it just returns some empty value. *

    - * {@link Answer} can be used to define the return values of unstubbed invocations. + * {@link Answer} can be used to define the return values of un-stubbed invocations. *

    * This implementation first tries the global configuration and if there is no global configuration then * it will use a default answer that returns zeros, empty collections, nulls, etc. @@ -1562,31 +1791,31 @@ public class Mockito extends ArgumentMatchers { /** * Optional Answer to be used with {@link Mockito#mock(Class, Answer)}. *

    - * {@link Answer} can be used to define the return values of unstubbed invocations. + * {@link Answer} can be used to define the return values of un-stubbed invocations. *

    * This implementation can be helpful when working with legacy code. - * Unstubbed methods often return null. If your code uses the object returned by an unstubbed call you get a NullPointerException. + * Un-stubbed methods often return null. If your code uses the object returned by an un-stubbed call, + * you get a NullPointerException. * This implementation of Answer returns SmartNull instead of null. - * SmartNull gives nicer exception message than NPE because it points out the line where unstubbed method was called. You just click on the stack trace. + * SmartNull gives nicer exception messages than NPEs, because it points out the + * line where the un-stubbed method was called. You just click on the stack trace. *

    * ReturnsSmartNulls first tries to return ordinary values (zeros, empty collections, empty string, etc.) * then it tries to return SmartNull. If the return type is final then plain null is returned. *

    - * ReturnsSmartNulls will be probably the default return values strategy in Mockito 4.0.0 - *

    * Example: *

    
          *   Foo mock = mock(Foo.class, RETURNS_SMART_NULLS);
          *
    -     *   //calling unstubbed method here:
    +     *   //calling un-stubbed method here:
          *   Stuff stuff = mock.getStuff();
          *
    -     *   //using object returned by unstubbed call:
    +     *   //using object returned by un-stubbed call:
          *   stuff.doSomething();
          *
          *   //Above doesn't yield NullPointerException this time!
          *   //Instead, SmartNullPointerException is thrown.
    -     *   //Exception's cause links to unstubbed mock.getStuff() - just click on the stack trace.
    +     *   //Exception's cause links to un-stubbed mock.getStuff() - just click on the stack trace.
          * 
    */ public static final Answer RETURNS_SMART_NULLS = Answers.RETURNS_SMART_NULLS; @@ -1594,7 +1823,7 @@ public class Mockito extends ArgumentMatchers { /** * Optional Answer to be used with {@link Mockito#mock(Class, Answer)} *

    - * {@link Answer} can be used to define the return values of unstubbed invocations. + * {@link Answer} can be used to define the return values of un-stubbed invocations. *

    * This implementation can be helpful when working with legacy code. *

    @@ -1695,21 +1924,21 @@ public class Mockito extends ArgumentMatchers { * Optional Answer to be used with {@link Mockito#mock(Class, Answer)} * *

    - * {@link Answer} can be used to define the return values of unstubbed invocations. + * {@link Answer} can be used to define the return values of un-stubbed invocations. *

    * This implementation can be helpful when working with legacy code. - * When this implementation is used, unstubbed methods will delegate to the real implementation. + * When this implementation is used, un-stubbed methods will delegate to the real implementation. * This is a way to create a partial mock object that calls real methods by default. *

    - * As usual you are going to read the partial mock warning: - * Object oriented programming is more less tackling complexity by dividing the complexity into separate, specific, SRPy objects. + * As usual, you are going to read the partial mock warning: + * Object oriented programming is more-or-less tackling complexity by dividing the complexity into separate, specific, SRPy objects. * How does partial mock fit into this paradigm? Well, it just doesn't... * Partial mock usually means that the complexity has been moved to a different method on the same object. * In most cases, this is not the way you want to design your application. *

    * However, there are rare cases when partial mocks come handy: * dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) - * However, I wouldn't use partial mocks for new, test-driven & well-designed code. + * However, I wouldn't use partial mocks for new, test-driven and well-designed code. *

    * Example: *

    
    @@ -1804,6 +2033,74 @@ public class Mockito extends ArgumentMatchers {
          */
         public static final Answer RETURNS_SELF = Answers.RETURNS_SELF;
     
    +    /**
    +     * Creates a mock object of the requested class or interface.
    +     * 

    + * See examples in javadoc for the {@link Mockito} class. + * + * @param reified don't pass any values to it. It's a trick to detect the class/interface you + * want to mock. + * @return the mock object. + * @since 4.10.0 + */ + @SafeVarargs + public static T mock(T... reified) { + return mock(withSettings(), reified); + } + + /** + * Creates a mock object of the requested class or interface with the given default answer. + *

    + * See examples in javadoc for the {@link Mockito} class. + * + * @param defaultAnswer the default answer to use. + * @param reified don't pass any values to it. It's a trick to detect the class/interface you + * want to mock. + * @return the mock object. + * @since 5.1.0 + */ + @SafeVarargs + public static T mock(@SuppressWarnings("rawtypes") Answer defaultAnswer, T... reified) { + return mock(withSettings().defaultAnswer(defaultAnswer), reified); + } + + /** + * Creates a mock object of the requested class or interface with the given name. + *

    + * See examples in javadoc for the {@link Mockito} class. + * + * @param name the mock name to use. + * @param reified don't pass any values to it. It's a trick to detect the class/interface you + * want to mock. + * @return the mock object. + * @since 5.1.0 + */ + @SafeVarargs + public static T mock(String name, T... reified) { + return mock(withSettings().name(name).defaultAnswer(RETURNS_DEFAULTS), reified); + } + + /** + * Creates a mock object of the requested class or interface with the given settings. + *

    + * See examples in javadoc for the {@link Mockito} class. + * + * @param settings the mock settings to use. + * @param reified don't pass any values to it. It's a trick to detect the class/interface you + * want to mock. + * @return the mock object. + * @since 5.1.0 + */ + @SafeVarargs + public static T mock(MockSettings settings, T... reified) { + if (reified == null || reified.length > 0) { + throw new IllegalArgumentException( + "Please don't pass any values here. Java will detect class automagically."); + } + + return mock(getClassOf(reified), settings); + } + /** * Creates mock object of given class or interface. *

    @@ -1812,7 +2109,6 @@ public class Mockito extends ArgumentMatchers { * @param classToMock class or interface to mock * @return mock object */ - @CheckReturnValue public static T mock(Class classToMock) { return mock(classToMock, withSettings()); } @@ -1832,11 +2128,8 @@ public static T mock(Class classToMock) { * @param name of the mock * @return mock object */ - @CheckReturnValue public static T mock(Class classToMock, String name) { - return mock(classToMock, withSettings() - .name(name) - .defaultAnswer(RETURNS_DEFAULTS)); + return mock(classToMock, withSettings().name(name).defaultAnswer(RETURNS_DEFAULTS)); } /** @@ -1851,7 +2144,6 @@ public static T mock(Class classToMock, String name) { * @return A {@link org.mockito.MockingDetails} instance. * @since 1.9.5 */ - @CheckReturnValue public static MockingDetails mockingDetails(Object toInspect) { return MOCKITO_CORE.mockingDetails(toInspect); } @@ -1871,11 +2163,10 @@ public static MockingDetails mockingDetails(Object toInspect) { *

    See examples in javadoc for {@link Mockito} class

    * * @param classToMock class or interface to mock - * @param defaultAnswer default answer for unstubbed methods + * @param defaultAnswer default answer for un-stubbed methods * * @return mock object */ - @CheckReturnValue public static T mock(Class classToMock, Answer defaultAnswer) { return mock(classToMock, withSettings().defaultAnswer(defaultAnswer)); } @@ -1883,7 +2174,7 @@ public static T mock(Class classToMock, Answer defaultAnswer) { /** * Creates a mock with some non-standard settings. *

    - * The number of configuration points for a mock grows + * The number of configuration points for a mock will grow, * so we need a fluent way to introduce new configuration without adding more and more overloaded Mockito.mock() methods. * Hence {@link MockSettings}. *

    
    @@ -1893,7 +2184,7 @@ public static  T mock(Class classToMock, Answer defaultAnswer) {
          * 
    * Use it carefully and occasionally. What might be reason your test needs non-standard mocks? * Is the code under test so complicated that it requires non-standard mocks? - * Wouldn't you prefer to refactor the code under test so it is testable in a simple way? + * Wouldn't you prefer to refactor the code under test, so that it is testable in a simple way? *

    * See also {@link Mockito#withSettings()} *

    @@ -1903,7 +2194,6 @@ public static T mock(Class classToMock, Answer defaultAnswer) { * @param mockSettings additional mock settings * @return mock object */ - @CheckReturnValue public static T mock(Class classToMock, MockSettings mockSettings) { return MOCKITO_CORE.mock(classToMock, mockSettings); } @@ -1913,7 +2203,7 @@ public static T mock(Class classToMock, MockSettings mockSettings) { *

    * Real spies should be used carefully and occasionally, for example when dealing with legacy code. *

    - * As usual you are going to read the partial mock warning: + * As usual, you are going to read the partial mock warning: * Object oriented programming tackles complexity by dividing the complexity into separate, specific, SRPy objects. * How does partial mock fit into this paradigm? Well, it just doesn't... * Partial mock usually means that the complexity has been moved to a different method on the same object. @@ -1921,7 +2211,7 @@ public static T mock(Class classToMock, MockSettings mockSettings) { *

    * However, there are rare cases when partial mocks come handy: * dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) - * However, I wouldn't use partial mocks for new, test-driven & well-designed code. + * However, I wouldn't use partial mocks for new, test-driven and well-designed code. *

    * Example: * @@ -1968,7 +2258,7 @@ public static T mock(Class classToMock, MockSettings mockSettings) { *

  17. Mockito *does not* delegate calls to the passed real instance, instead it actually creates a copy of it. * So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction * and their effect on real instance state. - * The corollary is that when an *unstubbed* method is called *on the spy* but *not on the real instance*, + * The corollary is that when an *un-stubbed* method is called *on the spy* but *not on the real instance*, * you won't see any effects on the real instance.
  18. * *
  19. Watch out for final methods. @@ -1987,11 +2277,14 @@ public static T mock(Class classToMock, MockSettings mockSettings) { * to spy on * @return a spy of the real object */ - @CheckReturnValue public static T spy(T object) { - return MOCKITO_CORE.mock((Class) object.getClass(), withSettings() - .spiedInstance(object) - .defaultAnswer(CALLS_REAL_METHODS)); + if (MockUtil.isMock(object)) { + throw new IllegalArgumentException( + "Please don't pass mock here. Spy is not allowed on mock."); + } + return MOCKITO_CORE.mock( + (Class) object.getClass(), + withSettings().spiedInstance(object).defaultAnswer(CALLS_REAL_METHODS)); } /** @@ -2021,12 +2314,244 @@ public static T spy(T object) { * @return a spy of the provided class * @since 1.10.12 */ - @Incubating - @CheckReturnValue public static T spy(Class classToSpy) { - return MOCKITO_CORE.mock(classToSpy, withSettings() - .useConstructor() - .defaultAnswer(CALLS_REAL_METHODS)); + return MOCKITO_CORE.mock( + classToSpy, withSettings().useConstructor().defaultAnswer(CALLS_REAL_METHODS)); + } + + /** + * Please refer to the documentation of {@link #spy(Class)}. + * + * @param reified don't pass any values to it. It's a trick to detect the class/interface you want to mock. + * @return spy object + * @since 4.10.0 + */ + @SafeVarargs + public static T spy(T... reified) { + if (reified.length > 0) { + throw new IllegalArgumentException( + "Please don't pass any values here. Java will detect class automagically."); + } + return spy(getClassOf(reified)); + } + + private static Class getClassOf(T[] array) { + return (Class) array.getClass().getComponentType(); + } + + /** + * Creates a thread-local mock controller for all static methods of the given class or interface. + * The returned object's {@link MockedStatic#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * Note: We recommend against mocking static methods of classes in the standard library or + * classes used by custom class loaders used to execute the block with the mocked class. A mock + * maker might forbid mocking static methods of know classes that are known to cause problems. + * Also, if a static method is a JVM-intrinsic, it cannot typically be mocked even if not + * explicitly forbidden. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock class or interface of which static mocks should be mocked. + * @return mock controller + */ + public static MockedStatic mockStatic(Class classToMock) { + return mockStatic(classToMock, withSettings()); + } + + /** + * Creates a thread-local mock controller for all static methods of the given class or interface. + * The returned object's {@link MockedStatic#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * Note: We recommend against mocking static methods of classes in the standard library or + * classes used by custom class loaders used to execute the block with the mocked class. A mock + * maker might forbid mocking static methods of know classes that are known to cause problems. + * Also, if a static method is a JVM-intrinsic, it cannot typically be mocked even if not + * explicitly forbidden. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock class or interface of which static mocks should be mocked. + * @param defaultAnswer the default answer when invoking static methods. + * @return mock controller + */ + public static MockedStatic mockStatic(Class classToMock, Answer defaultAnswer) { + return mockStatic(classToMock, withSettings().defaultAnswer(defaultAnswer)); + } + + /** + * Creates a thread-local mock controller for all static methods of the given class or interface. + * The returned object's {@link MockedStatic#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * Note: We recommend against mocking static methods of classes in the standard library or + * classes used by custom class loaders used to execute the block with the mocked class. A mock + * maker might forbid mocking static methods of know classes that are known to cause problems. + * Also, if a static method is a JVM-intrinsic, it cannot typically be mocked even if not + * explicitly forbidden. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock class or interface of which static mocks should be mocked. + * @param name the name of the mock to use in error messages. + * @return mock controller + */ + public static MockedStatic mockStatic(Class classToMock, String name) { + return mockStatic(classToMock, withSettings().name(name)); + } + + /** + * Creates a thread-local mock controller for all static methods of the given class or interface. + * The returned object's {@link MockedStatic#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * Note: We recommend against mocking static methods of classes in the standard library or + * classes used by custom class loaders used to execute the block with the mocked class. A mock + * maker might forbid mocking static methods of know classes that are known to cause problems. + * Also, if a static method is a JVM-intrinsic, it cannot typically be mocked even if not + * explicitly forbidden. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock class or interface of which static mocks should be mocked. + * @param mockSettings the settings to use where only name and default answer are considered. + * @return mock controller + */ + public static MockedStatic mockStatic(Class classToMock, MockSettings mockSettings) { + return MOCKITO_CORE.mockStatic(classToMock, mockSettings); + } + + /** + * Creates a thread-local mock controller for all constructions of the given class. + * The returned object's {@link MockedConstruction#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock non-abstract class of which constructions should be mocked. + * @param defaultAnswer the default answer for the first created mock. + * @param additionalAnswers the default answer for all additional mocks. For any access mocks, the + * last answer is used. If this array is empty, the {@code defaultAnswer} is used. + * @return mock controller + */ + public static MockedConstruction mockConstructionWithAnswer( + Class classToMock, Answer defaultAnswer, Answer... additionalAnswers) { + return mockConstruction( + classToMock, + context -> { + if (context.getCount() == 1 || additionalAnswers.length == 0) { + return withSettings().defaultAnswer(defaultAnswer); + } else if (context.getCount() > additionalAnswers.length) { + return withSettings() + .defaultAnswer(additionalAnswers[additionalAnswers.length - 1]); + } else { + return withSettings() + .defaultAnswer(additionalAnswers[context.getCount() - 2]); + } + }, + (mock, context) -> {}); + } + + /** + * Creates a thread-local mock controller for all constructions of the given class. + * The returned object's {@link MockedConstruction#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock non-abstract class of which constructions should be mocked. + * @return mock controller + */ + public static MockedConstruction mockConstruction(Class classToMock) { + return mockConstruction(classToMock, index -> withSettings(), (mock, context) -> {}); + } + + /** + * Creates a thread-local mock controller for all constructions of the given class. + * The returned object's {@link MockedConstruction#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock non-abstract class of which constructions should be mocked. + * @param mockInitializer a callback to prepare the methods on a mock after its instantiation. + * @return mock controller + */ + public static MockedConstruction mockConstruction( + Class classToMock, MockedConstruction.MockInitializer mockInitializer) { + return mockConstruction(classToMock, withSettings(), mockInitializer); + } + + /** + * Creates a thread-local mock controller for all constructions of the given class. + * The returned object's {@link MockedConstruction#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock non-abstract class of which constructions should be mocked. + * @param mockSettings the mock settings to use. + * @return mock controller + */ + public static MockedConstruction mockConstruction( + Class classToMock, MockSettings mockSettings) { + return mockConstruction(classToMock, context -> mockSettings); + } + + /** + * Creates a thread-local mock controller for all constructions of the given class. + * The returned object's {@link MockedConstruction#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock non-abstract class of which constructions should be mocked. + * @param mockSettingsFactory the mock settings to use. + * @return mock controller + */ + public static MockedConstruction mockConstruction( + Class classToMock, + Function mockSettingsFactory) { + return mockConstruction(classToMock, mockSettingsFactory, (mock, context) -> {}); + } + + /** + * Creates a thread-local mock controller for all constructions of the given class. + * The returned object's {@link MockedConstruction#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock non-abstract class of which constructions should be mocked. + * @param mockSettings the settings to use. + * @param mockInitializer a callback to prepare the methods on a mock after its instantiation. + * @return mock controller + */ + public static MockedConstruction mockConstruction( + Class classToMock, + MockSettings mockSettings, + MockedConstruction.MockInitializer mockInitializer) { + return mockConstruction(classToMock, index -> mockSettings, mockInitializer); + } + + /** + * Creates a thread-local mock controller for all constructions of the given class. + * The returned object's {@link MockedConstruction#close()} method must be called upon completing the + * test or the mock will remain active on the current thread. + *

    + * See examples in javadoc for {@link Mockito} class + * + * @param classToMock non-abstract class of which constructions should be mocked. + * @param mockSettingsFactory a function to create settings to use. + * @param mockInitializer a callback to prepare the methods on a mock after its instantiation. + * @return mock controller + */ + public static MockedConstruction mockConstruction( + Class classToMock, + Function mockSettingsFactory, + MockedConstruction.MockInitializer mockInitializer) { + return MOCKITO_CORE.mockConstruction(classToMock, mockSettingsFactory, mockInitializer); } /** @@ -2070,7 +2595,7 @@ public static T spy(Class classToSpy) { *

    * Stubbing can be overridden: for example common stubbing can go to fixture * setup but the test methods can override it. - * Please note that overridding stubbing is a potential code smell that points out too much stubbing. + * Please note that overriding stubbing is a potential code smell that points out too much stubbing. *

    * Once stubbed, the method will always return stubbed value regardless * of how many times it is called. @@ -2089,7 +2614,6 @@ public static T spy(Class classToSpy) { * @return OngoingStubbing object used to stub fluently. * Do not create a reference to this returned object. */ - @CheckReturnValue public static OngoingStubbing when(T methodCall) { return MOCKITO_CORE.when(methodCall); } @@ -2112,7 +2636,7 @@ public static OngoingStubbing when(T methodCall) { * Although it is possible to verify a stubbed invocation, usually it's just redundant. * Let's say you've stubbed foo.bar(). * If your code cares what foo.bar() returns then something else breaks(often before even verify() gets executed). - * If your code doesn't care what get(0) returns then it should not be stubbed. + * If your code doesn't care what foo.bar() returns then it should not be stubbed. * *

    * See examples in javadoc for {@link Mockito} class @@ -2120,7 +2644,6 @@ public static OngoingStubbing when(T methodCall) { * @param mock to be verified * @return mock object itself */ - @CheckReturnValue public static T verify(T mock) { return MOCKITO_CORE.verify(mock, times(1)); } @@ -2147,7 +2670,6 @@ public static T verify(T mock) { * * @return mock object itself */ - @CheckReturnValue public static T verify(T mock, VerificationMode mode) { return MOCKITO_CORE.verify(mock, mode); } @@ -2158,7 +2680,7 @@ public static T verify(T mock, VerificationMode mode) { *

    * Instead of #reset() please consider writing simple, small and focused test methods over lengthy, over-specified tests. * First potential code smell is reset() in the middle of the test method. This probably means you're testing too much. - * Follow the whisper of your test methods: "Please keep us small & focused on single behavior". + * Follow the whisper of your test methods: "Please keep us small and focused on single behavior". * There are several threads about it on mockito mailing list. *

    * The only reason we added reset() method is to @@ -2172,16 +2694,27 @@ public static T verify(T mock, VerificationMode mode) { * mock.add(1); * * reset(mock); - * //at this point the mock forgot any interactions & stubbing + * //at this point the mock forgot any interactions and stubbing * * * @param The Type of the mocks * @param mocks to be reset */ - public static void reset(T ... mocks) { + public static void reset(T... mocks) { MOCKITO_CORE.reset(mocks); } + /** + * Clears all mocks, type caches and instrumentations. + *

    + * By clearing Mockito's state, previously created mocks might begin to malfunction. This option can be used if + * Mockito's caches take up too much space or if the inline mock maker's instrumentation is causing performance + * issues in code where mocks are no longer used. Normally, you would not need to use this option. + */ + public static void clearAllCaches() { + MOCKITO_CORE.clearAllCaches(); + } + /** * Use this method in order to only clear invocations, when stubbing is non-trivial. Use-cases can be: *