├── .dependabot └── config.yml ├── .gitattributes ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── build.gradle ├── gradle ├── cdeliveryboy-release.gradle ├── dk1.asc.enc ├── manifest.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main └── java │ └── info │ └── solidsoft │ └── mockito │ └── java8 │ ├── AssertionMatcher.java │ ├── LambdaAwareHandyReturnValues.java │ ├── LambdaMatcher.java │ ├── SneakyThrow.java │ ├── ThrowingConsumer.java │ ├── ThrowingPredicate.java │ └── api │ ├── WithAdditionalMatchers.java │ ├── WithBDDMockito.java │ ├── WithMatchers.java │ └── WithMockito.java └── test └── java └── info └── solidsoft └── mockito └── java8 ├── AssertionMatcherTest.java ├── LambdaMatcherStubbingTest.java ├── LambdaMatcherTest.java ├── api ├── WithBDDMockitoTest.java ├── WithMockitoAndAdditionalMatchersTest.java └── WithMockitoTest.java └── domain ├── ShipSearchCriteria.java ├── TacticalStation.java └── TopedoType.java /.dependabot/config.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | update_configs: 4 | - package_manager: "java:gradle" 5 | directory: "/" 6 | update_schedule: "daily" 7 | target_branch: "devel" 8 | 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Allow gradle.bat to retain CRLF 5 | gradlew.bat text eol=crlf 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | 4 | .idea/ 5 | *.iml 6 | out/ 7 | 8 | .poject 9 | .settings 10 | .classpath 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: groovy 2 | 3 | before_install: 4 | # Secrets (including encrypted PGP key) are not available in PR - skip release configuration to do not fail build 5 | - | 6 | if [ "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then 7 | # There is problem with aborting build on command in if failure - http://steven.casagrande.io/articles/travis-ci-and-if-statements/ 8 | openssl aes-256-cbc -K $encrypted_68da27d62c62_key -iv $encrypted_68da27d62c62_iv -in gradle/dk1.asc.enc -d | gpg --fast-import || travis_terminate 1 9 | export GRADLE_OPTS='-Dorg.gradle.daemon=true -Dorg.gradle.project.signing.keyId=0694F057 -Dorg.gradle.project.signing.secretKeyRingFile=$HOME/.gnupg/secring.gpg -Dorg.gradle.project.signing.password=' 10 | fi; 11 | - "export TRAVIS_COMMIT_MSG=$(git log --format=%B -n 1 $TRAVIS_COMMIT)" 12 | - git config user.email "szpak-ci@users.noreply.github.com" 13 | - git config user.name "Szpak CI Bot" 14 | # Chandler for release notes synchronization 15 | - ruby --version 16 | - rvm install 2.4.1 17 | - ruby --version 18 | - gem install --no-document chandler -v 0.7.0 19 | 20 | install: true 21 | script: 22 | - ./gradlew --version 23 | - ./gradlew prepareForCiBuild -s -i -Prelease.disableChecks && ./gradlew ciBuild -s -i -Prelease.disableChecks -PchangelogSync 24 | 25 | before_cache: 26 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 27 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 28 | - rm -fr $HOME/.gradle/caches/*/scripts/ 29 | - rm -fr $HOME/.gradle/caches/*/scripts-remapped/ 30 | - rm -fr $HOME/.gradle/caches/*/fileHashes/ 31 | - rm -fr $HOME/.gradle/caches/transforms-1/transforms-1.lock 32 | cache: 33 | directories: 34 | - $HOME/.gradle/caches/ 35 | - $HOME/.gradle/wrapper/ 36 | - $HOME/.rvm/ 37 | 38 | env: 39 | global: 40 | - secure: Z5GqUbePIpNIXSlT7eR+XiGJNMiCZA8hVeztjvkXbG4eBuUNp0aAkFsNWp+4AvEn6dmBBmFF7OMmrzj6poqWM7GkbevFnMeYewjla1TllRv/6KlvyvkHwGxIB/uD8etY+WR8fLi1054nfu9uG2FHLCfQaGt7OBL8sQtp8rFtFrNpHV+UL2YJenUSN+Ztz/RfgGpPXFa5iOyeNIez0e/jtNAktZq9hyroTsEEtH0Zf/AcF4CPjPJQHizxT78z4mMD4NFxXxZiOj5RZ52wYeGnPMcGhITFY7jd9ZdxlQW4u/UeJZ1KvlN26he2xpddrhsqn+ZFjSfJSYHc46di17AFm7t9XngAc5NoK3rvueRGaSczpRBxBTft0CKAx1E/tfp+W2D88pIKPbhH/qnofTYLqLUNIxZOMNOOqk8eUTBSId9bXULHH+5YTPUKt7ytxGZvendKCEHYVBoAxh6vvuBr1UG7ExR8X/kgkHtdWM0lVDDjjZMeR8xsgfeiyowayxUAq8bELW23A133E9zvSxYmhQeQvU9y1KUZk1VZp1MHQe/dLqe2LKrxASwMlR16lRpFp6jXBPK6KG6pNZUHGaX5Nd30AdbxrBmFUvtoWBb/z5KsazMxcjo/Fqmt36Uq3Noj2z2ln6ENTmt4Dvm+d+1Zfdt1g21F9V5gfZgfdAIGYsY= 41 | - secure: C3R/cMmlI0MaJnc70Dh3zLM5e8ybyiCXR198wdgx67JKHH14lMeJ/1z20o3/0doy1dsdqIUo9jdCboHP5imQxg/1dheF0m5sy5WoBXIjpFM/+KK0XPlqeAteh7REzawi8EXoGknSS1CFOvwoM8URM72IBlG+AMLYe9h+j05kQ3a/Sscrame/i3/dHm28udUDx10CDa9JqbrIHrdK6M1DJTpobN68p/4fO6MEU48eVUfFv9DF3gOWbV9FtB3NkOx+xGEm7fgEiR7czSo5JKAFO1vUtZdLuio6780Ufvr2QG1kgrZLyhQarH/rzgxAsRLfqCgo8I9xor0MPtVMl2GNkD/+wLWNJ2uIT5LE/Da+lGck454e+YgXpgp3WK6w9kLquZQc3EpkjT9ugHYV4hj3R2eLuBTWk9Zs9HxynSCcGqNHK+dCbvekAA9kloX7FQhJlFUVg1w3uDfLxrG2f+sTLFyHz8heB+rNFFUDVfG7IJwkaUDZ7GbAkqApgE6WfZeE0hsIGqPFXwTzjAhiKBrLdoP5GbYdqN9RT3yNHw9+guFpsncNmYkUa3WAmZxvG64g9BguwFbMq/zARxjyLFKl+x+8126g502NVFT46CzHypKDB/9+/4Eb5BMM7qoT+Q1JPZBKpcPz1FhhKATBYVPXTAPOlXNIJre+8VYmNGkUYIA= 42 | - secure: sCNfMTvn/ziW+SI7MWKpAuUKpx0Ah92KGU2DxgZloMmKQJ9l2Y75nHs1t4cgCkkDh4TYO4XLuFAH04fPS8WHQS2D6hLuKxTstO3wE7or4VeK/DOnm7uLjO4gK51BUcbN8ejcI6F5iM8zM3A4Dp/PT0bYBbPFmxBcS8aWohcGwzbwGxCV5/AcGdn37DdWJIbHfNtktJEVYkBXdvfyGiJt6mrS+XSBKLRM9PMEYY6zJPjCoIWNar/1pPFcgqgHSothHS/gCvWLudN35E4IxDgQICJ4YpKwHA4xdoCY9WHmI2qYUk7XXmr8aJG3LeCrTabnwtyPTsQYoeVz+CTraIVBLhc8bZfC5XfFN9rdjh9EML5bqUcGB2d4AdKBtaPVY29PQ2JCBgQAPqsaxFUPAkxmBHo4O6ELSAoOKIXpr1kybf718+S44SE5EqyVviZf5MdqMLPI3AgSxYTQi9yNGxqVOM99TGmUOdgB/daPBuIlJ08vqrGCliznQ7hZgLgp48pQlCMIsRpp953VGGxqDJadp2/aZenxpLqP3ZJ7IctWVDgMszqw82ufrn9Xuhrpk/wJrtmY5QgJU+/qKCP+TeJ6orDZY25D8alGyIKjJZNakVK43ZKaAW2laDc+6BT3nSQchDeZ8vkk6wXPPiEkO18xF7B/GZGi/NeHcqWle1lzxDI= 43 | - secure: RLy6LUJkxhUI4NsQLKxGs4hdXwiAEGp9tvlfiuGtaAuLoQajDuaLDGtr1VrO9qjUvKkK4DVneu6dsyGxTjV6g+O+Zr8I9ybgaP+7GH75xuq+Eey1jKr+9aPm5OuWbgco1WC3YCTfyBPAOhAXU0Tx+HAJwAZMPRPp7W+nHAFToxBQg3m6mlMbRWnqtEYZ+ZVukKDYBatnJ7mFTAk0644f6spX170Z+X1BlNzK9rRhLfotwHej0EtFfuV8YJHHQutQou/kAf7keUL2Hg4v0TjNQfkqwutBHfRlwm7/Zm5sUUf5ZNuc/iKrgR2CnAGskpqVAYn1kSt4oKo2ckghUdRJLFehTWc0PLhM5mEeqFSYPqer6NXPSO7pcGYct6hzrpEP77lCKlPc61oyljDmHdWNHIlrhLNWoSeb3OI5PmPEJF8O/kRCZ4kOoNxe92poLfg3RbwvSGDl1SNOhxCEIjwj8BzWREYT6iYTXfk9PkkiCf8r3FBf2I5CdfySbLLz5yEibjBCkgVlzmOpFO1WNNbUjQuBqTPfl9eUnGqZYrYJpa2ZZOeoQgSfIFc+YU32W+MLsqq29PMHfhpP5kNJJhpbmmmWAqGF22Ocb1R2qUWgphuiscQdFTOPx4s1YzVQspmK/r4cITIPuUvKbG9Le7xFx4elOKYZtpMZuFMW3DkDjng= 44 | 45 | matrix: 46 | include: 47 | - jdk: openjdk8 48 | - jdk: openjdk9 49 | env: SKIP_RELEASE=true 50 | - jdk: openjdk10 51 | env: SKIP_RELEASE=true 52 | - jdk: openjdk11 53 | env: SKIP_RELEASE=true 54 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # mockito-java8 changelog 2 | 3 | ## 2.5.0 - 2018-10-19 4 | 5 | - Accept lambda expressions declaring checked exceptions - #12, #18 - PR by @Ferada 6 | - Upgrade default Mockito dependency to 2.23.0 7 | - Migrate internal tests to JUnit 5 8 | 9 | ## 2.4.0 - 2018-09-23 10 | 11 | - Preliminary Java 11 support - #17 12 | - Upgrade default Mockito dependency to 2.22.0 13 | - Upgrade Gradle wrapper to 4.10.2 14 | 15 | ## 2.3.0 - 2018-03-17 16 | 17 | - Preliminary Java 10 support - #16 18 | - Upgrade default Mockito dependency to 2.16.0 19 | - Upgrade Gradle wrapper to 4.6 20 | 21 | ## 2.2.0 - 2017-10-07 22 | 23 | - Explicitly add JPMS module name to MANIFEST - #14 24 | - Upgrade default Mockito dependency to 2.10.0 25 | - Upgrade Gradle wrapper to 4.2.1 26 | 27 | ## 2.1.0 - 2017-06-25 28 | 29 | - Preliminary Java 9 support (with typetools upgrade to 0.5.0) 30 | - Method argument names availability (with `-parameters` compilation switch) 31 | - Upgrade default Mockito dependency to 2.8.47 32 | - Upgrade Gradle wrapper to 3.5.1 33 | - Upgrade other dependencies 34 | - Add automatic `CHANGELOG.md` sync with GitHub releases 35 | 36 | ## 2.0.1 - 2017-02-09 37 | 38 | - Add OSGI metadata to MENIFEST.MF - [#13](https://github.com/szpak/mockito-java8/pull/13) - contribution by @nickstolwijk 39 | 40 | ## 2.0.0 - 2016-10-20 41 | 42 | - Switch to a stable Mockito 2.x version (2.2.5) 43 | - Update other dependencies 44 | - Switch releasing to Continuous Delivery with [CDeliveryBoy](https://github.com/szpak/CDeliveryBoy/) 45 | 46 | 47 | Older changes available via [GitHub release mechanism](https://github.com/szpak/mockito-java8/releases) 48 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mockito-Java8 [![Build Status](https://travis-ci.org/szpak/mockito-java8.svg?branch=master)](https://travis-ci.org/szpak/mockito-java8) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/info.solidsoft.mockito/mockito-java8/badge.svg)](https://maven-badges.herokuapp.com/maven-central/info.solidsoft.mockito/mockito-java8) 2 | 3 | Mockito add-ons leveraging Java 8 and lambda expressions to make mocking even more compact. 4 | 5 | ## Quick start 6 | 7 | ### Lambda matcher 8 | 9 | Allows for stubbing with matcher logic defined within a lambda expression. Useful when working with complex classes pass as an argument. 10 | 11 | ``` 12 | given(ts.findNumberOfShipsInRangeByCriteria( 13 | argLambda(c -> c.getMinimumRange() > 1000))).willReturn(4); 14 | ``` 15 | 16 | ### Argument Captor - Java 8 edition 17 | 18 | Allows to use ArgumentCaptor in one line (here with AssertJ): 19 | 20 | ``` 21 | verify(ts).findNumberOfShipsInRangeByCriteria( 22 | assertArg(sc -> assertThat(sc.getMinimumRange()).isLessThan(2000))); 23 | ``` 24 | 25 | ### Mockito API methods available via interfaces (without static imports) 26 | 27 | Allows to use methods from Mockito API without the need to use static imports. It is enough to make your test class implement `WithBDDMockito` 28 | interface to have all methods from Mockito API available directly (especially useful for Eclipse users). 29 | 30 | ``` 31 | class SpaceShipTest implements WithBDDMockito { 32 | //stub and verify as usual without static imports 33 | } 34 | ``` 35 | 36 | Available interfaces: [`WithBDDMockito`](https://github.com/szpak/mockito-java8/blob/master/src/main/java/info/solidsoft/mockito/java8/api/WithBDDMockito.java), 37 | [`WithMockito`](https://github.com/szpak/mockito-java8/blob/master/src/main/java/info/solidsoft/mockito/java8/api/WithMockito.java) and 38 | [`WithAdditionalMatchers`](https://github.com/szpak/mockito-java8/blob/master/src/main/java/info/solidsoft/mockito/java8/api/WithAdditionalMatchers.java). 39 | 40 | 41 | ## Configuration in a project 42 | 43 | mockito-java8 jars are available in Maven Central. 44 | 45 | ### Gradle 46 | 47 | ``` 48 | testCompile 'info.solidsoft.mockito:mockito-java8:2.5.0' 49 | ``` 50 | 51 | ### Maven 52 | 53 | ``` 54 | 55 | info.solidsoft.mockito 56 | mockito-java8 57 | 2.5.0 58 | test 59 | 60 | ``` 61 | 62 | ### Other 63 | 64 | Click Maven Central badge [![Maven Central](https://maven-badges.herokuapp.com/maven-central/info.solidsoft.mockito/mockito-java8/badge.svg)](https://maven-badges.herokuapp.com/maven-central/info.solidsoft.mockito/mockito-java8) to get configuration snippets for SBT, Ivy and more. 65 | 66 | ## Mockito compatibility 67 | 68 | Mockito-Java8 has two development lines. Versions 1.x (and 0.3.x) should be compatible with Mockito 1.10.12+ and 2.0.x-beta up to 2.0.21-beta. 69 | Versions 2.x supports the new matchers API and should be compatible with Mockito 2.0.22-beta and newer versions. 70 | 71 | Documentation for versions 1.x can be found in a separate [branch](https://github.com/szpak/mockito-java8/tree/1.x). 72 | 73 | ## Provided add-ons 74 | 75 | ### Lambda matcher 76 | 77 | Allows to define matcher logic within a lambda expression. Useful when working with complex classes pass as an argument. 78 | 79 | ``` 80 | @Immutable 81 | class ShipSearchCriteria { 82 | int minimumRange; 83 | int numberOfPhasers; 84 | } 85 | ``` 86 | 87 | ``` 88 | @Test 89 | public void shouldAllowToUseLambdaInStubbing() { 90 | //given 91 | given(ts.findNumberOfShipsInRangeByCriteria( 92 | argLambda(c -> c.getMinimumRange() > 1000))).willReturn(4); 93 | //expect 94 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))) 95 | .isEqualTo(4); 96 | //expect 97 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))) 98 | .isEqualTo(0); 99 | } 100 | ``` 101 | 102 | In comparison the same logic implemented with a custom Answer in Java 7: 103 | 104 | ``` 105 | @Test 106 | public void stubbingWithCustomAnswerShouldBeLonger() { //old way 107 | //given 108 | given(ts.findNumberOfShipsInRangeByCriteria(any())).willAnswer(new Answer() { 109 | @Override 110 | public Integer answer(InvocationOnMock invocation) throws Throwable { 111 | Object[] args = invocation.getArguments(); 112 | ShipSearchCriteria criteria = (ShipSearchCriteria) args[0]; 113 | if (criteria.getMinimumRange() > 1000) { 114 | return 4; 115 | } else { 116 | return 0; 117 | } 118 | } 119 | }); 120 | //expect 121 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))) 122 | .isEqualTo(4); 123 | //expect 124 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))) 125 | .isEqualTo(0); 126 | } 127 | ``` 128 | 129 | Even Java 8 and less readable constructions don't help too much: 130 | 131 | ``` 132 | @Test 133 | public void stubbingWithCustomAnswerShouldBeLongerEvenAsLambda() { //old way 134 | //given 135 | given(ts.findNumberOfShipsInRangeByCriteria(any())).willAnswer(invocation -> { 136 | ShipSearchCriteria criteria = (ShipSearchCriteria) invocation.getArguments()[0]; 137 | return criteria.getMinimumRange() > 1000 ? 4 : 0; 138 | }); 139 | //expect 140 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))) 141 | .isEqualTo(4); 142 | //expect 143 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))) 144 | .isEqualTo(0); 145 | } 146 | ``` 147 | 148 | ### Argument Captor - Java 8 edition 149 | 150 | Allows to use ArgumentCaptor in one line: 151 | 152 | ``` 153 | @Test 154 | public void shouldAllowToUseAssertionInLambda() { 155 | //when 156 | ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 157 | //then 158 | verify(ts).findNumberOfShipsInRangeByCriteria( 159 | assertArg(sc -> assertThat(sc.getMinimumRange()).isLessThan(2000))); 160 | } 161 | ``` 162 | 163 | In comparison to 3 lines in the classic way: 164 | 165 | ``` 166 | @Test 167 | public void shouldAllowToUseArgumentCaptorInClassicWay() { //old way 168 | //when 169 | ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 170 | //then 171 | ArgumentCaptor captor = 172 | ArgumentCaptor.forClass(ShipSearchCriteria.class); 173 | verify(ts).findNumberOfShipsInRangeByCriteria(captor.capture()); 174 | assertThat(captor.getValue().getMinimumRange()).isLessThan(2000); 175 | } 176 | ``` 177 | 178 | ### Mockito API methods available via interfaces (without static imports) 179 | 180 | Allows to use methods from Mockito API without the need to use static imports. It is enough to make your test class implement `WithBDDMockito` 181 | interface to have all methods from stubbing/mockito Mockito API available directly. 182 | 183 | ``` 184 | //no need to use static imports! 185 | 186 | public class SpaceShipTest implements WithBDDMockito { 187 | 188 | @Test 189 | public void shouldVerifyMethodExecution() { 190 | //given 191 | TacticalStation tsSpy = spy(TacticalStation.class); 192 | willDoNothing().given(tsSpy).fireTorpedo(2); 193 | //when 194 | tsSpy.fireTorpedo(2); 195 | tsSpy.fireTorpedo(2); 196 | //then 197 | then(tsSpy).should(times(2)).fireTorpedo(2); 198 | } 199 | } 200 | ``` 201 | 202 | The same code would work fine with a bunch of static imports. Of course they can be hidden in IDE and usually do not disturb much. Nevertheless 203 | to be able to write just a method name (e.g. `mock(TacticalStation.class)`) without a class is it required to press ALT-ENTER (in IntelliJ IDEA) 204 | to add each static import on the first usage of a given method in a test class. The situation is even worse in Eclipse where it is 205 | [required](http://stackoverflow.com/a/290756/313516) to earlier add `BDDMockito` to "Favorites" in "Content Assist" to make it suggested by IDE. 206 | 207 | Mockito methods are provided by 3 base interfaces, being an entry point for given set of methods: 208 | - [`WithBDDMockito`](https://github.com/szpak/mockito-java8/blob/master/src/main/java/info/solidsoft/mockito/java8/api/WithBDDMockito.java) - stubbing/mocking API in BDD style 209 | - [`WithMockito`](https://github.com/szpak/mockito-java8/blob/master/src/main/java/info/solidsoft/mockito/java8/api/WithMockito.java) - classic stubbing/mocking API 210 | - [`WithAdditionalMatchers`](https://github.com/szpak/mockito-java8/blob/master/src/main/java/info/solidsoft/mockito/java8/api/WithAdditionalMatchers.java) - additional matchers 211 | 212 | 213 | ## Rationale 214 | 215 | Mockito-Java8 is a side effect of my short presentation [Java 8 brings power to testing!](https://speakerdeck.com/szpak/java-8-brings-power-to-testing) 216 | which I gave at GeeCON TDD 2015 and DevConf.cz 2015. In my speech, using 4 examples, I showed how Java 8 - namely lambda expressions - can simplify testing tools. 217 | 218 | 219 | ## Limitations 220 | 221 | Unfortunately there is a set of nice Java 8 related features which cannot be implemented without a non backward compatible changes in Mockito core and 222 | therefore cannot be implemented as an add-on. A good news is that [Mockito 3.0](https://github.com/mockito/mockito/issues/297) is planned to require 223 | Java 8 making it all possible. 224 | 225 | 226 | ## Java 9 compatibility 227 | 228 | The project is automatically tested with Java 9 (and Java 10) in the CI environment. At least the base scenarios should work with Java 9. Feel free to report an [issue](https://github.com/szpak/mockito-java8/issues/) if you encounter any mockito-java8 specific problem. 229 | 230 | The project's JAR artifact contains an Automatic-Module-Name manifest attribute. It's value - `info.solidsoft.mockito.mockito-java8` - is used 231 | as the name of the automatic module defined by that JAR file when it is placed on the Java 9 module path. This allows to explicitly require 232 | mockito-java8 in other projects. 233 | 234 | The mockito-java8 dependencies itself will be declared explicitly once available in required projects. 235 | 236 | 237 | ## Additional information 238 | 239 | mockito-java8 has been written by Marcin Zajączkowski. The author can be contacted directly via email: mszpak ATT wp DOTT pl. 240 | There is also Marcin's blog available: [Solid Soft](http://blog.solidsoft.info/) - working code is not enough. 241 | 242 | mockito-java8 is a separate project and is NOT supported by The Mockito Core Team. 243 | 244 | The library is licensed under the terms of [the Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt). 245 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath 'info.solidsoft.gradle:cdeliveryboy:0.8.0' 7 | classpath('com.toomuchcoding:uptodate-gradle-plugin:1.0.1') { 8 | //Workaround: 0.7.2 is not available in Maven Central - https://github.com/marcingrzejszczak/uptodate-gradle-plugin/issues/2 9 | exclude group: 'org.codehaus.groovy.modules.http-builder', module: 'http-builder' 10 | } 11 | } 12 | } 13 | 14 | apply plugin: 'java' 15 | apply plugin: 'com.toomuchcoding.uptodate' 16 | apply from: "$rootDir/gradle/cdeliveryboy-release.gradle" 17 | apply from: "$rootDir/gradle/manifest.gradle" 18 | 19 | ext.mockitoVersion = findProperty('mockitoVersion') ?: '2.27.0' 20 | 21 | sourceCompatibility = 1.8 22 | 23 | tasks.withType(JavaCompile) { 24 | options.compilerArgs << '-parameters' 25 | } 26 | 27 | test { 28 | useJUnitPlatform() 29 | 30 | afterSuite { desc, result -> 31 | if (!desc.parent) { 32 | //Workaround - https://github.com/gradle/gradle/issues/7452 33 | if (result.testCount == 0) { 34 | throw new IllegalStateException("No tests were found. Failing the build") 35 | } 36 | } 37 | } 38 | } 39 | 40 | repositories { 41 | mavenCentral() 42 | } 43 | 44 | dependencies { 45 | compile "org.mockito:mockito-core:$mockitoVersion" 46 | compile 'net.jodah:typetools:0.6.1' 47 | 48 | testCompile 'org.junit.jupiter:junit-jupiter-api:5.4.2' 49 | testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.4.2' 50 | testCompile "org.mockito:mockito-junit-jupiter:$mockitoVersion" 51 | testCompile 'org.assertj:assertj-core:3.13.1' 52 | } 53 | 54 | //Disable JavaDoc doclint on Java 8 - it fails on invalid JavaDoc elements in mockito-core jar 55 | if (JavaVersion.current().isJava8Compatible()) { 56 | tasks.withType(Javadoc) { 57 | options.addStringOption('Xdoclint:none', '-quiet') 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /gradle/cdeliveryboy-release.gradle: -------------------------------------------------------------------------------- 1 | //Continuous Delivery release configuration with CDeliveryBoy 2 | 3 | apply plugin: 'info.solidsoft.cdeliveryboy' 4 | 5 | cDeliveryBoy { 6 | tasks { 7 | promoteRepositoryTask = "releaseRepository" 8 | } 9 | nexus { 10 | autoPromote = true 11 | } 12 | } 13 | 14 | nexusStaging { 15 | packageGroup = "info.solidsoft" 16 | } 17 | 18 | scmVersion { 19 | versionIncrementer 'incrementMinor' 20 | hooks { 21 | pre 'fileUpdate', [file: 'README.md', pattern: {previousVersion, context -> /'info\.solidsoft\.mockito:mockito-java8:$previousVersion'/}, 22 | replacement: {currentVersion, context -> "'info.solidsoft.mockito:mockito-java8:$currentVersion'"}] 23 | pre 'fileUpdate', [file: 'README.md', pattern: {previousVersion, context -> /$previousVersion<\/version>$/}, 24 | replacement: {currentVersion, context -> "$currentVersion"}] 25 | pre 'fileUpdate', [file : 'CHANGELOG.md', pattern: { previousVersion, context -> /^##\ ${context.currentVersion}\ -\ Unreleased$/ }, 26 | replacement: { currentVersion, context -> "## $currentVersion - ${new Date().format('yyyy-MM-dd')}" }] 27 | } 28 | } 29 | 30 | project.group = "info.solidsoft.mockito" 31 | //Beware: All release/version related changes should be put before that line which triggers (lazy) version evaluation 32 | project.version = scmVersion.version 33 | 34 | String repoSlug = 'szpak/mockito-java8' 35 | modifyPom { 36 | project { 37 | name 'Mockito-Java8' 38 | description 'Mockito add-ons leveraging Java 8 and lambda expressions to make mocking even more compact' 39 | url "https://github.com/$repoSlug" 40 | inceptionYear '2015' 41 | 42 | scm { 43 | url "https://github.com/$repoSlug" 44 | connection "scm:https://github.com/$repoSlug" 45 | developerConnection "scm:git://github.com/$repoSlug" 46 | } 47 | 48 | licenses { 49 | license { 50 | name 'The Apache Software License, Version 2.0' 51 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 52 | distribution 'repo' 53 | } 54 | } 55 | 56 | developers { 57 | developer { 58 | id 'szpak' 59 | name 'Marcin Zajączkowski' 60 | email 'mszpak ATT wp DOTT pl' 61 | roles { 62 | role 'developer' 63 | role 'despot' 64 | } 65 | } 66 | } 67 | } 68 | } 69 | 70 | if (hasProperty('changelogSync')) { 71 | 72 | task syncChangelog(type: Exec) { 73 | doFirst { logger.info("Synchronizing changelog with GitHub for version ${project.version}") } 74 | commandLine 'chandler', 'push', "release/${project.version}", '--tag-prefix=release/' 75 | } 76 | 77 | syncChangelog { 78 | onlyIf { ciBuild.inReleaseMode } 79 | mustRunAfter releaseRepository 80 | if (project.tasks.findByName("publishPlugins")) { 81 | mustRunAfter publishPlugins 82 | } 83 | } 84 | ciBuild.dependsOn syncChangelog 85 | } 86 | -------------------------------------------------------------------------------- /gradle/dk1.asc.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szpak/mockito-java8/7c9f30b0d53445a9dd0c7a380cdab58a0079d716/gradle/dk1.asc.enc -------------------------------------------------------------------------------- /gradle/manifest.gradle: -------------------------------------------------------------------------------- 1 | //Manifest content configuration 2 | 3 | apply plugin: 'osgi' 4 | 5 | Date buildDateAndTime = new Date() 6 | ext.buildDate = buildDateAndTime.format('yyyy-MM-dd') 7 | ext.buildTime = buildDateAndTime.format('HH:mm:ss.SSSZ') 8 | 9 | jar { 10 | manifest { 11 | attributes( 12 | 'Created-By': "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})".toString(), 13 | 'Build-Date': buildDate, 14 | 'Build-Time': buildTime, 15 | 'Build-Revision': scmVersion.scmPosition.revision, 16 | 'Specification-Title': project.name, 17 | 'Specification-Version': project.version, 18 | 'Specification-Vendor': 'SolidSoft.info', 19 | 'Implementation-Title': project.name, 20 | 'Implementation-Version': project.version, 21 | 'Implementation-Vendor': 'SolidSoft.info', 22 | 'Automatic-Module-Name': 'info.solidsoft.mockito.mockito-java8' 23 | ) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szpak/mockito-java8/7c9f30b0d53445a9dd0c7a380cdab58a0079d716/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip 4 | distributionSha256Sum=b49c6da1b2cb67a0caf6c7480630b51c70a11ca2016ff2f555eaeda863143a29 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'mockito-java8' 2 | -------------------------------------------------------------------------------- /src/main/java/info/solidsoft/mockito/java8/AssertionMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8; 7 | 8 | import org.mockito.ArgumentMatcher; 9 | import org.mockito.Incubating; 10 | import org.mockito.Mockito; 11 | 12 | import java.util.function.Consumer; 13 | 14 | /** 15 | * Allows creating inlined ArgumentCaptor with a lambda expression. 16 | *

17 | * With Java 8 and lambda expressions ArgumentCaptor can be inlined: 18 | * 19 | *


20 |  * {@literal @}Test
21 |  * public void shouldAllowToUseAssertionInLambda() {
22 |  *   //when
23 |  *   ts.findNumberOfShipsInRangeByCriteria(searchCriteria);
24 |  *   //then
25 |  *   verify(ts).findNumberOfShipsInRangeByCriteria(assertArg(sc -> assertThat(sc.getMinimumRange()).isLessThan(2000)));
26 |  * }
27 |  * 
28 | * 29 | * in comparison to 3 lines in the classic way: 30 | * 31 | *

32 |  * {@literal @}Test
33 |  * public void shouldAllowToUseArgumentCaptorInClassicWay() {  //old way
34 |  *     //when
35 |  *     ts.findNumberOfShipsInRangeByCriteria(searchCriteria);
36 |  *     //then
37 |  *     ArgumentCaptor captor = ArgumentCaptor.forClass(ShipSearchCriteria.class);
38 |  *     verify(ts).findNumberOfShipsInRangeByCriteria(captor.capture());
39 |  *     assertThat(captor.getValue().getMinimumRange()).isLessThan(2000);
40 |  * }
41 |  *
42 |  * AssertJ assertions (assertThat()) used in lambda generate meaningful error messages in face of failure, but any other assertion can be
43 |  * used if needed/preferred.
44 |  *
45 |  * @param  type of argument
46 |  *
47 |  * @author Marcin Zajączkowski
48 |  */
49 | @SuppressWarnings("WeakerAccess")
50 | public class AssertionMatcher implements ArgumentMatcher {
51 | 
52 |     private static final LambdaAwareHandyReturnValues handyReturnValues = new LambdaAwareHandyReturnValues();
53 | 
54 |     private final Consumer consumer;
55 |     private String errorMessage;
56 | 
57 |     private AssertionMatcher(Consumer consumer) {
58 |         this.consumer = consumer;
59 |     }
60 | 
61 |     @SuppressWarnings("unchecked")
62 |     @Override
63 |     public boolean matches(T argument) {
64 |         try {
65 |             consumer.accept(argument);
66 |             return true;
67 |         } catch (AssertionError e) {
68 |             errorMessage = e.getMessage();
69 |             return false;
70 |         }
71 |     }
72 | 
73 |     @Override
74 |     public String toString() {
75 |         return "AssertionMatcher reported: " + errorMessage;
76 |     }
77 | 
78 |     public static  T assertArg(Consumer consumer) {
79 |         argThat(consumer);
80 |         return handyReturnValues.returnForConsumerLambda(consumer);
81 |     }
82 | 
83 |     /**
84 |      * A variant of assertArg(Consumer) for lambdas declaring checked exceptions.
85 |      */
86 |     @Incubating
87 |     public static  T assertArgThrowing(ThrowingConsumer throwingConsumer) {
88 |         argThat(throwingConsumer.uncheck());
89 |         return handyReturnValues.returnForConsumerLambdaChecked(throwingConsumer);
90 |     }
91 | 
92 |     @SuppressWarnings("ResultOfMethodCallIgnored")
93 |     private static  void argThat(Consumer consumer) {
94 |         Mockito.argThat(new AssertionMatcher<>(consumer));
95 |     }
96 | }
97 | 


--------------------------------------------------------------------------------
/src/main/java/info/solidsoft/mockito/java8/LambdaAwareHandyReturnValues.java:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright (C) 2015 Marcin Zajączkowski.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0.
 5 |  */
 6 | package info.solidsoft.mockito.java8;
 7 | 
 8 | import net.jodah.typetools.TypeResolver;
 9 | import org.mockito.internal.util.Primitives;
10 | 
11 | import java.util.function.Consumer;
12 | 
13 | /**
14 |  * Extended version of HandyReturnValues which can resolve safe return type also for Consumer argument.
15 |  *
16 |  * Under the hood it uses TypeTools library which is used to work also for primitive argument types (to not throw NullPointerException).
17 |  *
18 |  * @author Marcin Zajączkowski
19 |  */
20 | class LambdaAwareHandyReturnValues {
21 | 
22 |      T returnForConsumerLambda(Consumer consumer) {
23 |         return internalReturnForLambda(consumer, Consumer.class);
24 |     }
25 | 
26 |      T returnForConsumerLambdaChecked(ThrowingConsumer throwingConsumer) {
27 |         return internalReturnForLambda(throwingConsumer, ThrowingConsumer.class);
28 |     }
29 | 
30 |     @SuppressWarnings("unchecked")
31 |     private  T internalReturnForLambda(Object consumer, Class consumerType) {
32 |         Class[] typeArgs = TypeResolver.resolveRawArguments(consumerType, consumer.getClass());
33 |         return (T) Primitives.defaultValue(typeArgs[0]);
34 |     }
35 | }
36 | 


--------------------------------------------------------------------------------
/src/main/java/info/solidsoft/mockito/java8/LambdaMatcher.java:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Copyright (C) 2015 Marcin Zajączkowski.
  3 |  *
  4 |  * Licensed under the Apache License, Version 2.0.
  5 |  */
  6 | package info.solidsoft.mockito.java8;
  7 | 
  8 | import org.mockito.ArgumentMatcher;
  9 | import org.mockito.Incubating;
 10 | 
 11 | import java.util.function.Predicate;
 12 | 
 13 | import static org.mockito.ArgumentMatchers.argThat;
 14 | 
 15 | /**
 16 |  * Allows creating inlined argument matcher with a lambda expression.
 17 |  * 

18 | * With Java 8 and lambda expressions ArgumentCaptor can be expressed inline: 19 | * 20 | *


 21 |  *{@literal @}Test
 22 |  * public void shouldAllowToUseLambdaInStubbing() {
 23 |  *     //given
 24 |  *     given(ts.findNumberOfShipsInRangeByCriteria(argLambda(c -> c.getMinimumRange() > 1000))).willReturn(4);
 25 |  *     //expect
 26 |  *     assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))).isEqualTo(4);
 27 |  *     //expect
 28 |  *     assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))).isEqualTo(0);
 29 |  * }
 30 |  * 
31 | *

32 | * In comparison the same logic implemented with a custom Answer in Java 7: 33 | * 34 | *


 35 |  *{@literal @}Test
 36 |  * public void stubbingWithCustomAnswerShouldBeLonger() {  //old way
 37 |  *     //given
 38 |  *     given(ts.findNumberOfShipsInRangeByCriteria(any())).willAnswer(new Answer() {
 39 |  *        {@literal @}Override
 40 |  *         public Integer answer(InvocationOnMock invocation) throws Throwable {
 41 |  *             Object[] args = invocation.getArguments();
 42 |  *             ShipSearchCriteria criteria = (ShipSearchCriteria) args[0];
 43 |  *             if (criteria.getMinimumRange() > 1000) {
 44 |  *                 return 4;
 45 |  *             } else {
 46 |  *                 return 0;
 47 |  *             }
 48 |  *         }
 49 |  *     });
 50 |  *     //expect
 51 |  *     assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))).isEqualTo(4);
 52 |  *     //expect
 53 |  *     assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))).isEqualTo(0);
 54 |  * }
 55 |  * 
56 | *

57 | * Even Java 8 alone and using less readable constructions produce less compact code: 58 | * 59 | *


 60 |  *{@literal @}Test
 61 |  * public void stubbingWithCustomAsnwerShouldBeLongerEvenAsLambda() {  //old way
 62 |  *     //given
 63 |  *     given(ts.findNumberOfShipsInRangeByCriteria(any())).willAnswer(invocation -> {
 64 |  *         ShipSearchCriteria criteria = (ShipSearchCriteria) invocation.getArguments()[0];
 65 |  *         return criteria.getMinimumRange() > 1000 ? 4 : 0;
 66 |  *     });
 67 |  *     //expect
 68 |  *     assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))).isEqualTo(4);
 69 |  *     //expect
 70 |  *     assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))).isEqualTo(0);
 71 |  * }
 72 |  * 
73 | * 74 | * @param type of argument 75 | * 76 | * @author Marcin Zajączkowski 77 | */ 78 | @SuppressWarnings("WeakerAccess") 79 | public class LambdaMatcher implements ArgumentMatcher { 80 | 81 | private final ArgumentMatcher backendMatcher; //TODO: Could it be done with just one matcher? 82 | 83 | private LambdaMatcher(Predicate lambda, String description) { 84 | this.backendMatcher = new ArgumentMatcher() { 85 | @Override 86 | public boolean matches(T item) { 87 | try { 88 | return lambda.test(item); 89 | } catch (Exception e) { 90 | throw new RuntimeException(e); //Could be potentially tricked with CheckedPredicate.uncheck(), but kept for backward compatibility 91 | } 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return description; 97 | } 98 | }; 99 | } 100 | 101 | @Override 102 | public boolean matches(T item) { 103 | return backendMatcher.matches(item); 104 | } 105 | 106 | @Override 107 | public String toString() { 108 | return backendMatcher.toString(); 109 | } 110 | 111 | public static T argLambda(Predicate lambda) { 112 | return argLambda(lambda, "Inline lambda expression - add description in code to get more detailed error message"); 113 | } 114 | 115 | public static T argLambda(Predicate lambda, String description) { 116 | return argThat(new LambdaMatcher<>(lambda, description)); 117 | } 118 | 119 | /** 120 | * A variant of argLambda(Predicate) for lambdas declaring checked ecceptions. 121 | */ 122 | @Incubating 123 | public static T argLambdaThrowing(ThrowingPredicate throwingLambda) { 124 | return argLambda(throwingLambda.uncheck(), "Inline lambda expression - add description in code to get more detailed error message"); 125 | } 126 | 127 | /** 128 | * A variant of argLambda(Predicate) for lambdas declaring checked exceptions. 129 | */ 130 | @Incubating 131 | public static T argLambdaThrowing(ThrowingPredicate throwingLambda, String description) { 132 | return argThat(new LambdaMatcher<>(throwingLambda.uncheck(), description)); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/info/solidsoft/mockito/java8/SneakyThrow.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Mockito contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8; 7 | 8 | /** 9 | * An internal class providing a hack to trick the compiler to accept a lack of a declaration of checked exception in a caller. 10 | * 11 | * Based on the idea presented by Grzegorz Piwowarek in his presentation: The Dark Side of Java 8. 12 | * https://4comprehension.com/sneakily-throwing-exceptions-in-lambda-expressions-in-java/ 13 | */ 14 | class SneakyThrow { 15 | 16 | @SuppressWarnings("unchecked") 17 | static R sneakyRethrow(Exception e) throws E { 18 | throw (E) e; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/info/solidsoft/mockito/java8/ThrowingConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Mockito contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8; 7 | 8 | import org.mockito.Incubating; 9 | 10 | import java.util.function.Consumer; 11 | 12 | import static info.solidsoft.mockito.java8.SneakyThrow.sneakyRethrow; 13 | 14 | @FunctionalInterface 15 | @Incubating 16 | public interface ThrowingConsumer { 17 | 18 | void accept(T t) throws Exception; 19 | 20 | default Consumer uncheck() { 21 | return t -> { 22 | try { 23 | this.accept(t); 24 | } catch (Exception e) { 25 | sneakyRethrow(e); 26 | } 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/info/solidsoft/mockito/java8/ThrowingPredicate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Mockito contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8; 7 | 8 | import org.mockito.Incubating; 9 | 10 | import java.util.function.Predicate; 11 | 12 | import static info.solidsoft.mockito.java8.SneakyThrow.sneakyRethrow; 13 | 14 | @FunctionalInterface 15 | @Incubating 16 | public interface ThrowingPredicate { 17 | 18 | boolean test(T t) throws Exception; 19 | 20 | default Predicate uncheck() { 21 | return t -> { 22 | try { 23 | return this.test(t); 24 | } catch (Exception e) { 25 | return sneakyRethrow(e); 26 | } 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/info/solidsoft/mockito/java8/api/WithAdditionalMatchers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Mockito contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.api; 7 | 8 | import org.mockito.AdditionalMatchers; 9 | import org.mockito.Incubating; 10 | 11 | /** 12 | * An entry point to Mockito additional matchers. 13 | *

14 | * Created as an alternative approach to static imports. A test class can implement that interface to make methods from 15 | * {@link AdditionalMatchers} class directly available. 16 | *

17 | * Should be used with {@link WithBDDMockito} or {@link WithMockito}. 18 | * 19 | * @see WithBDDMockito 20 | * @see WithMockito 21 | * 22 | * @author Marcin Zajączkowski 23 | * @since 1.0.0 24 | */ 25 | @Incubating 26 | public interface WithAdditionalMatchers { 27 | 28 | /** 29 | * Delegates call to {@link AdditionalMatchers#geq(Comparable)}. 30 | */ 31 | default > T geq(T value) { 32 | return AdditionalMatchers.geq(value); 33 | } 34 | 35 | /** 36 | * Delegates call to {@link AdditionalMatchers#geq(byte)}. 37 | */ 38 | default byte geq(byte value) { 39 | return AdditionalMatchers.geq(value); 40 | } 41 | 42 | /** 43 | * Delegates call to {@link AdditionalMatchers#geq(double)}. 44 | */ 45 | default double geq(double value) { 46 | return AdditionalMatchers.geq(value); 47 | } 48 | 49 | /** 50 | * Delegates call to {@link AdditionalMatchers#geq(float)}. 51 | */ 52 | default float geq(float value) { 53 | return AdditionalMatchers.geq(value); 54 | } 55 | 56 | /** 57 | * Delegates call to {@link AdditionalMatchers#geq(int)}. 58 | */ 59 | default int geq(int value) { 60 | return AdditionalMatchers.geq(value); 61 | } 62 | 63 | /** 64 | * Delegates call to {@link AdditionalMatchers#geq(long)}. 65 | */ 66 | default long geq(long value) { 67 | return AdditionalMatchers.geq(value); 68 | } 69 | 70 | /** 71 | * Delegates call to {@link AdditionalMatchers#geq(short)}. 72 | */ 73 | default short geq(short value) { 74 | return AdditionalMatchers.geq(value); 75 | } 76 | 77 | /** 78 | * Delegates call to {@link AdditionalMatchers#leq(Comparable)}. 79 | */ 80 | default > T leq(T value) { 81 | return AdditionalMatchers.leq(value); 82 | } 83 | 84 | /** 85 | * Delegates call to {@link AdditionalMatchers#leq(byte)}. 86 | */ 87 | default byte leq(byte value) { 88 | return AdditionalMatchers.leq(value); 89 | } 90 | 91 | /** 92 | * Delegates call to {@link AdditionalMatchers#leq(double)}. 93 | */ 94 | default double leq(double value) { 95 | return AdditionalMatchers.leq(value); 96 | } 97 | 98 | /** 99 | * Delegates call to {@link AdditionalMatchers#leq(float)}. 100 | */ 101 | default float leq(float value) { 102 | return AdditionalMatchers.leq(value); 103 | } 104 | 105 | /** 106 | * Delegates call to {@link AdditionalMatchers#leq(int)}. 107 | */ 108 | default int leq(int value) { 109 | return AdditionalMatchers.leq(value); 110 | } 111 | 112 | /** 113 | * Delegates call to {@link AdditionalMatchers#leq(long)}. 114 | */ 115 | default long leq(long value) { 116 | return AdditionalMatchers.leq(value); 117 | } 118 | 119 | /** 120 | * Delegates call to {@link AdditionalMatchers#leq(short)}. 121 | */ 122 | default short leq(short value) { 123 | return AdditionalMatchers.leq(value); 124 | } 125 | 126 | /** 127 | * Delegates call to {@link AdditionalMatchers#gt(Comparable)}. 128 | */ 129 | default > T gt(T value) { 130 | return AdditionalMatchers.gt(value); 131 | } 132 | 133 | /** 134 | * Delegates call to {@link AdditionalMatchers#gt(byte)}. 135 | */ 136 | default byte gt(byte value) { 137 | return AdditionalMatchers.gt(value); 138 | } 139 | 140 | /** 141 | * Delegates call to {@link AdditionalMatchers#gt(double)}. 142 | */ 143 | default double gt(double value) { 144 | return AdditionalMatchers.gt(value); 145 | } 146 | 147 | /** 148 | * Delegates call to {@link AdditionalMatchers#gt(float)}. 149 | */ 150 | default float gt(float value) { 151 | return AdditionalMatchers.gt(value); 152 | } 153 | 154 | /** 155 | * Delegates call to {@link AdditionalMatchers#gt(int)}. 156 | */ 157 | default int gt(int value) { 158 | return AdditionalMatchers.gt(value); 159 | } 160 | 161 | /** 162 | * Delegates call to {@link AdditionalMatchers#gt(long)}. 163 | */ 164 | default long gt(long value) { 165 | return AdditionalMatchers.gt(value); 166 | } 167 | 168 | /** 169 | * Delegates call to {@link AdditionalMatchers#gt(short)}. 170 | */ 171 | default short gt(short value) { 172 | return AdditionalMatchers.gt(value); 173 | } 174 | 175 | /** 176 | * Delegates call to {@link AdditionalMatchers#lt(Comparable)}. 177 | */ 178 | default > T lt(T value) { 179 | return AdditionalMatchers.lt(value); 180 | } 181 | 182 | /** 183 | * Delegates call to {@link AdditionalMatchers#lt(byte)}. 184 | */ 185 | default byte lt(byte value) { 186 | return AdditionalMatchers.lt(value); 187 | } 188 | 189 | /** 190 | * Delegates call to {@link AdditionalMatchers#lt(double)}. 191 | */ 192 | default double lt(double value) { 193 | return AdditionalMatchers.lt(value); 194 | } 195 | 196 | /** 197 | * Delegates call to {@link AdditionalMatchers#lt(float)}. 198 | */ 199 | default float lt(float value) { 200 | return AdditionalMatchers.lt(value); 201 | } 202 | 203 | /** 204 | * Delegates call to {@link AdditionalMatchers#lt(int)}. 205 | */ 206 | default int lt(int value) { 207 | return AdditionalMatchers.lt(value); 208 | } 209 | 210 | /** 211 | * Delegates call to {@link AdditionalMatchers#lt(long)}. 212 | */ 213 | default long lt(long value) { 214 | return AdditionalMatchers.lt(value); 215 | } 216 | 217 | /** 218 | * Delegates call to {@link AdditionalMatchers#lt(short)}. 219 | */ 220 | default short lt(short value) { 221 | return AdditionalMatchers.lt(value); 222 | } 223 | 224 | /** 225 | * Delegates call to {@link AdditionalMatchers#cmpEq(Comparable)}. 226 | */ 227 | default > T cmpEq(T value) { 228 | return AdditionalMatchers.cmpEq(value); 229 | } 230 | 231 | /** 232 | * Delegates call to {@link AdditionalMatchers#find(String)}. 233 | */ 234 | default String find(String regex) { 235 | return AdditionalMatchers.find(regex); 236 | } 237 | 238 | /** 239 | * Delegates call to {@link AdditionalMatchers#aryEq(T[])}. 240 | */ 241 | default T[] aryEq(T[] value) { 242 | return AdditionalMatchers.aryEq(value); 243 | } 244 | 245 | /** 246 | * Delegates call to {@link AdditionalMatchers#aryEq(short[])}. 247 | */ 248 | default short[] aryEq(short[] value) { 249 | return AdditionalMatchers.aryEq(value); 250 | } 251 | 252 | /** 253 | * Delegates call to {@link AdditionalMatchers#aryEq(long[])}. 254 | */ 255 | default long[] aryEq(long[] value) { 256 | return AdditionalMatchers.aryEq(value); 257 | } 258 | 259 | /** 260 | * Delegates call to {@link AdditionalMatchers#aryEq(int[])}. 261 | */ 262 | default int[] aryEq(int[] value) { 263 | return AdditionalMatchers.aryEq(value); 264 | } 265 | 266 | /** 267 | * Delegates call to {@link AdditionalMatchers#aryEq(float[])}. 268 | */ 269 | default float[] aryEq(float[] value) { 270 | return AdditionalMatchers.aryEq(value); 271 | } 272 | 273 | /** 274 | * Delegates call to {@link AdditionalMatchers#aryEq(double[])}. 275 | */ 276 | default double[] aryEq(double[] value) { 277 | return AdditionalMatchers.aryEq(value); 278 | } 279 | 280 | /** 281 | * Delegates call to {@link AdditionalMatchers#aryEq(char[])}. 282 | */ 283 | default char[] aryEq(char[] value) { 284 | return AdditionalMatchers.aryEq(value); 285 | } 286 | 287 | /** 288 | * Delegates call to {@link AdditionalMatchers#aryEq(byte[])}. 289 | */ 290 | default byte[] aryEq(byte[] value) { 291 | return AdditionalMatchers.aryEq(value); 292 | } 293 | 294 | /** 295 | * Delegates call to {@link AdditionalMatchers#aryEq(boolean[])}. 296 | */ 297 | default boolean[] aryEq(boolean[] value) { 298 | return AdditionalMatchers.aryEq(value); 299 | } 300 | 301 | /** 302 | * Delegates call to {@link AdditionalMatchers#and(boolean, boolean)}. 303 | */ 304 | default boolean and(boolean first, boolean second) { 305 | return AdditionalMatchers.and(first, second); 306 | } 307 | 308 | /** 309 | * Delegates call to {@link AdditionalMatchers#and(byte, byte)}. 310 | */ 311 | default byte and(byte first, byte second) { 312 | return AdditionalMatchers.and(first, second); 313 | } 314 | 315 | /** 316 | * Delegates call to {@link AdditionalMatchers#and(char, char)}. 317 | */ 318 | default char and(char first, char second) { 319 | return AdditionalMatchers.and(first, second); 320 | } 321 | 322 | /** 323 | * Delegates call to {@link AdditionalMatchers#and(double, double)}. 324 | */ 325 | default double and(double first, double second) { 326 | return AdditionalMatchers.and(first, second); 327 | } 328 | 329 | /** 330 | * Delegates call to {@link AdditionalMatchers#and(float, float)}. 331 | */ 332 | default float and(float first, float second) { 333 | return AdditionalMatchers.and(first, second); 334 | } 335 | 336 | /** 337 | * Delegates call to {@link AdditionalMatchers#and(int, int)}. 338 | */ 339 | default int and(int first, int second) { 340 | return AdditionalMatchers.and(first, second); 341 | } 342 | 343 | /** 344 | * Delegates call to {@link AdditionalMatchers#and(long, long)}. 345 | */ 346 | default long and(long first, long second) { 347 | return AdditionalMatchers.and(first, second); 348 | } 349 | 350 | /** 351 | * Delegates call to {@link AdditionalMatchers#and(short, short)}. 352 | */ 353 | default short and(short first, short second) { 354 | return AdditionalMatchers.and(first, second); 355 | } 356 | 357 | /** 358 | * Delegates call to {@link AdditionalMatchers#and(T, T)}. 359 | */ 360 | default T and(T first, T second) { 361 | return AdditionalMatchers.and(first, second); 362 | } 363 | 364 | /** 365 | * Delegates call to {@link AdditionalMatchers#or(boolean, boolean)}. 366 | */ 367 | default boolean or(boolean first, boolean second) { 368 | return AdditionalMatchers.or(first, second); 369 | } 370 | 371 | /** 372 | * Delegates call to {@link AdditionalMatchers#or(T, T)}. 373 | */ 374 | default T or(T first, T second) { 375 | return AdditionalMatchers.or(first, second); 376 | } 377 | 378 | /** 379 | * Delegates call to {@link AdditionalMatchers#or(short, short)}. 380 | */ 381 | default short or(short first, short second) { 382 | return AdditionalMatchers.or(first, second); 383 | } 384 | 385 | /** 386 | * Delegates call to {@link AdditionalMatchers#or(long, long)}. 387 | */ 388 | default long or(long first, long second) { 389 | return AdditionalMatchers.or(first, second); 390 | } 391 | 392 | /** 393 | * Delegates call to {@link AdditionalMatchers#or(int, int)}. 394 | */ 395 | default int or(int first, int second) { 396 | return AdditionalMatchers.or(first, second); 397 | } 398 | 399 | /** 400 | * Delegates call to {@link AdditionalMatchers#or(float, float)}. 401 | */ 402 | default float or(float first, float second) { 403 | return AdditionalMatchers.or(first, second); 404 | } 405 | 406 | /** 407 | * Delegates call to {@link AdditionalMatchers#or(double, double)}. 408 | */ 409 | default double or(double first, double second) { 410 | return AdditionalMatchers.or(first, second); 411 | } 412 | 413 | /** 414 | * Delegates call to {@link AdditionalMatchers#or(char, char)}. 415 | */ 416 | default char or(char first, char second) { 417 | return AdditionalMatchers.or(first, second); 418 | } 419 | 420 | /** 421 | * Delegates call to {@link AdditionalMatchers#or(byte, byte)}. 422 | */ 423 | default byte or(byte first, byte second) { 424 | return AdditionalMatchers.or(first, second); 425 | } 426 | 427 | /** 428 | * Delegates call to {@link AdditionalMatchers#not(T)}. 429 | */ 430 | default T not(T first) { 431 | return AdditionalMatchers.not(first); 432 | } 433 | 434 | /** 435 | * Delegates call to {@link AdditionalMatchers#not(short)}. 436 | */ 437 | default short not(short first) { 438 | return AdditionalMatchers.not(first); 439 | } 440 | 441 | /** 442 | * Delegates call to {@link AdditionalMatchers#not(int)}. 443 | */ 444 | default int not(int first) { 445 | return AdditionalMatchers.not(first); 446 | } 447 | 448 | /** 449 | * Delegates call to {@link AdditionalMatchers#not(long)}. 450 | */ 451 | default long not(long first) { 452 | return AdditionalMatchers.not(first); 453 | } 454 | 455 | /** 456 | * Delegates call to {@link AdditionalMatchers#not(float)}. 457 | */ 458 | default float not(float first) { 459 | return AdditionalMatchers.not(first); 460 | } 461 | 462 | /** 463 | * Delegates call to {@link AdditionalMatchers#not(double)}. 464 | */ 465 | default double not(double first) { 466 | return AdditionalMatchers.not(first); 467 | } 468 | 469 | /** 470 | * Delegates call to {@link AdditionalMatchers#not(char)}. 471 | */ 472 | default char not(char first) { 473 | return AdditionalMatchers.not(first); 474 | } 475 | 476 | /** 477 | * Delegates call to {@link AdditionalMatchers#not(boolean)}. 478 | */ 479 | default boolean not(boolean first) { 480 | return AdditionalMatchers.not(first); 481 | } 482 | 483 | /** 484 | * Delegates call to {@link AdditionalMatchers#not(byte)}. 485 | */ 486 | default byte not(byte first) { 487 | return AdditionalMatchers.not(first); 488 | } 489 | 490 | /** 491 | * Delegates call to {@link AdditionalMatchers#eq(double, double)}. 492 | */ 493 | default double eq(double value, double delta) { 494 | return AdditionalMatchers.eq(value, delta); 495 | } 496 | 497 | /** 498 | * Delegates call to {@link AdditionalMatchers#eq(float, float)}. 499 | */ 500 | default float eq(float value, float delta) { 501 | return AdditionalMatchers.eq(value, delta); 502 | } 503 | } 504 | -------------------------------------------------------------------------------- /src/main/java/info/solidsoft/mockito/java8/api/WithBDDMockito.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Mockito contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.api; 7 | 8 | import org.mockito.BDDMockito; 9 | import org.mockito.Incubating; 10 | import org.mockito.stubbing.Answer; 11 | 12 | /** 13 | * An entry point to Mockito stubbing/mocking API in BDD style with basic matchers. 14 | *

15 | * Created as an alternative approach to static imports. A test class can implement that interface to make all 16 | * the methods from {@link BDDMockito} class directly available. 17 | *

18 | * Sample test in Behavior-driven development style: 19 | * 20 | *


 21 |  * //no static Mockito imports needed!
 22 |  *
 23 |  * class ShopTest implements WithMockito {
 24 |  *
 25 |  *   private Seller seller = mock(Seller.class);
 26 |  *   private Shop shop = new Shop(seller);
 27 |  *
 28 |  *   public void shouldBuyBread() {
 29 |  *     //given
 30 |  *     given(seller.askForBread()).willReturn(new Bread());
 31 |  *     //when
 32 |  *     Goods goods = shop.buyBread();
 33 |  *     //then
 34 |  *     assertThat(goods.containBread()).isTrue();
 35 |  *   }
 36 |  * }
 37 |  * 
38 | *

39 | * 40 | * For BDD style mock verification {@link BDDMockito.Then} can be used: 41 | *


 42 |  *   person.ride(bike);
 43 |  *   person.ride(bike);
 44 |  *
 45 |  *   then(person).should(times(2)).ride(bike);
 46 |  *   then(police).shouldHaveZeroInteractions();
 47 |  * 
48 | * 49 | * See {@link WithMockito} if Arrange-Act-Assert approach is preferred over BDD. 50 | *

51 | * If more sophisticated matchers are needed see {@link WithAdditionalMatchers} interface. 52 | *

53 | * Based on an idea proposed by David Gageot: 54 | * http://blog.javabien.net/2014/04/23/what-if-assertj-used-java-8/ 55 | * 56 | * @see WithMockito 57 | * @see WithAdditionalMatchers 58 | * 59 | * @author Marcin Zajączkowski 60 | * @since 1.0.0 61 | */ 62 | @Incubating 63 | public interface WithBDDMockito extends WithMockito { 64 | 65 | /** 66 | * Delegates call to {@link BDDMockito#given(Object)} 67 | */ 68 | default BDDMockito.BDDMyOngoingStubbing given(T methodCall) { 69 | return BDDMockito.given(methodCall); 70 | } 71 | 72 | /** 73 | * Delegates call to {@link BDDMockito#then(Object)} 74 | */ 75 | default BDDMockito.Then then(T mock) { 76 | return BDDMockito.then(mock); 77 | } 78 | 79 | /** 80 | * Delegates call to {@link BDDMockito#willThrow(Throwable...)} 81 | */ 82 | default BDDMockito.BDDStubber willThrow(Throwable... toBeThrown) { 83 | return BDDMockito.willThrow(toBeThrown); 84 | } 85 | 86 | /** 87 | * Delegates call to {@link BDDMockito#willThrow(Class)} 88 | */ 89 | default BDDMockito.BDDStubber willThrow(Class toBeThrown) { 90 | return BDDMockito.willThrow(toBeThrown); 91 | } 92 | 93 | /** 94 | * Delegates call to {@link BDDMockito#doAnswer(Answer)} 95 | */ 96 | default BDDMockito.BDDStubber willAnswer(Answer answer) { 97 | return BDDMockito.willAnswer(answer); 98 | } 99 | 100 | /** 101 | * Delegates call to {@link BDDMockito#doNothing()} 102 | */ 103 | default BDDMockito.BDDStubber willDoNothing() { 104 | return BDDMockito.willDoNothing(); 105 | } 106 | 107 | /** 108 | * Delegates call to {@link BDDMockito#doReturn(Object)} 109 | */ 110 | default BDDMockito.BDDStubber willReturn(Object toBeReturned) { 111 | return BDDMockito.willReturn(toBeReturned); 112 | } 113 | 114 | /** 115 | * Delegates call to {@link BDDMockito#doReturn(Object, Object...)} 116 | */ 117 | default BDDMockito.BDDStubber willReturn(Object toBeReturned, Object... toBeReturnedNext) { 118 | return BDDMockito.willReturn(toBeReturned, toBeReturnedNext); 119 | } 120 | 121 | /** 122 | * Delegates call to {@link BDDMockito#doCallRealMethod()} 123 | */ 124 | default BDDMockito.BDDStubber willCallRealMethod() { 125 | return BDDMockito.willCallRealMethod(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/info/solidsoft/mockito/java8/api/WithMatchers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Mockito contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.api; 7 | 8 | import org.mockito.ArgumentMatcher; 9 | import org.mockito.ArgumentMatchers; 10 | 11 | import java.util.Collection; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | 16 | /** 17 | * An internal interface being an entry point to Mockito basic matchers. 18 | *

19 | * Created only to organize internal entry points structure. Basic matchers are transitively available via 20 | * {@link WithBDDMockito} and {@link WithMockito} interfaces. Additional matcher are available via 21 | * {@link WithAdditionalMatchers} interface. 22 | * 23 | * @see WithAdditionalMatchers 24 | * @see WithBDDMockito 25 | * @see WithMockito 26 | * 27 | * @author Marcin Zajączkowski 28 | * @since 1.0.0 29 | */ 30 | interface WithMatchers { 31 | 32 | /** 33 | * Delegates call to {@link ArgumentMatchers#anyBoolean()}. 34 | */ 35 | default boolean anyBoolean() { 36 | return ArgumentMatchers.anyBoolean(); 37 | } 38 | 39 | /** 40 | * Delegates call to {@link ArgumentMatchers#anyByte()}. 41 | */ 42 | default byte anyByte() { 43 | return ArgumentMatchers.anyByte(); 44 | } 45 | 46 | /** 47 | * Delegates call to {@link ArgumentMatchers#anyChar()}. 48 | */ 49 | default char anyChar() { 50 | return ArgumentMatchers.anyChar(); 51 | } 52 | 53 | /** 54 | * Delegates call to {@link ArgumentMatchers#anyInt()}. 55 | */ 56 | default int anyInt() { 57 | return ArgumentMatchers.anyInt(); 58 | } 59 | 60 | /** 61 | * Delegates call to {@link ArgumentMatchers#anyLong()}. 62 | */ 63 | default long anyLong() { 64 | return ArgumentMatchers.anyLong(); 65 | } 66 | 67 | /** 68 | * Delegates call to {@link ArgumentMatchers#anyFloat()}. 69 | */ 70 | default float anyFloat() { 71 | return ArgumentMatchers.anyFloat(); 72 | } 73 | 74 | /** 75 | * Delegates call to {@link ArgumentMatchers#anyDouble()}. 76 | */ 77 | default double anyDouble() { 78 | return ArgumentMatchers.anyDouble(); 79 | } 80 | 81 | /** 82 | * Delegates call to {@link ArgumentMatchers#anyShort()}. 83 | */ 84 | default short anyShort() { 85 | return ArgumentMatchers.anyShort(); 86 | } 87 | 88 | /** 89 | * Delegates call to {@link ArgumentMatchers#anyObject()}. 90 | * 91 | * @deprecated This will be removed in Mockito 3.0. 92 | */ 93 | @Deprecated 94 | default T anyObject() { 95 | return ArgumentMatchers.anyObject(); 96 | } 97 | 98 | /** 99 | * Delegates call to {@link ArgumentMatchers#anyVararg()}. 100 | * 101 | * @deprecated This will be removed in Mockito 3.0. 102 | */ 103 | @Deprecated 104 | default T anyVararg() { 105 | return ArgumentMatchers.anyVararg(); 106 | } 107 | 108 | /** 109 | * Delegates call to {@link ArgumentMatchers#any(Class)}. 110 | */ 111 | default T any(Class clazz) { 112 | return ArgumentMatchers.any(clazz); 113 | } 114 | 115 | /** 116 | * Delegates call to {@link ArgumentMatchers#any()}. 117 | */ 118 | default T any() { 119 | return ArgumentMatchers.any(); 120 | } 121 | 122 | /** 123 | * Delegates call to {@link ArgumentMatchers#anyString()}. 124 | */ 125 | default String anyString() { 126 | return ArgumentMatchers.anyString(); 127 | } 128 | 129 | /** 130 | * Delegates call to {@link ArgumentMatchers#anyList()}. 131 | */ 132 | default List anyList() { 133 | return ArgumentMatchers.anyList(); 134 | } 135 | 136 | /** 137 | * Delegates call to {@link ArgumentMatchers#anyListOf(Class)}. 138 | * 139 | * @deprecated This will be removed in Mockito 3.0. 140 | */ 141 | @Deprecated 142 | default List anyListOf(Class clazz) { 143 | return ArgumentMatchers.anyListOf(clazz); 144 | } 145 | 146 | /** 147 | * Delegates call to {@link ArgumentMatchers#anySet()}. 148 | */ 149 | default Set anySet() { 150 | return ArgumentMatchers.anySet(); 151 | } 152 | 153 | /** 154 | * Delegates call to {@link ArgumentMatchers#anySetOf(Class)}. 155 | * 156 | * @deprecated This will be removed in Mockito 3.0. 157 | */ 158 | @Deprecated 159 | default Set anySetOf(Class clazz) { 160 | return ArgumentMatchers.anySetOf(clazz); 161 | } 162 | 163 | /** 164 | * Delegates call to {@link ArgumentMatchers#anyMap()}. 165 | */ 166 | default Map anyMap() { 167 | return ArgumentMatchers.anyMap(); 168 | } 169 | 170 | /** 171 | * Delegates call to {@link ArgumentMatchers#anyMapOf(Class, Class)}. 172 | * 173 | * @deprecated This will be removed in Mockito 3.0. 174 | */ 175 | @Deprecated 176 | default Map anyMapOf(Class keyClazz, Class valueClazz) { 177 | return ArgumentMatchers.anyMapOf(keyClazz, valueClazz); 178 | } 179 | 180 | /** 181 | * Delegates call to {@link ArgumentMatchers#anyCollection()}. 182 | */ 183 | default Collection anyCollection() { 184 | return ArgumentMatchers.anyCollection(); 185 | } 186 | 187 | /** 188 | * Delegates call to {@link ArgumentMatchers#anyCollectionOf(Class)}. 189 | * 190 | * @deprecated This will be removed in Mockito 3.0. 191 | */ 192 | @Deprecated 193 | default Collection anyCollectionOf(Class clazz) { 194 | return ArgumentMatchers.anyCollectionOf(clazz); 195 | } 196 | 197 | /** 198 | * Delegates call to {@link ArgumentMatchers#anyIterable()}. 199 | * 200 | * @since 2.0.0 201 | */ 202 | default Iterable anyIterable() { 203 | return ArgumentMatchers.anyIterable(); 204 | } 205 | 206 | /** 207 | * Delegates call to {@link ArgumentMatchers#anyIterableOf(Class)}. 208 | * 209 | * @since 2.0.0 210 | * @deprecated This will be removed in Mockito 3.0. 211 | */ 212 | @Deprecated 213 | default Iterable anyIterableOf(Class clazz) { 214 | return ArgumentMatchers.anyIterableOf(clazz); 215 | } 216 | 217 | /** 218 | * Delegates call to {@link ArgumentMatchers#isA(Class)}. 219 | */ 220 | default T isA(Class clazz) { 221 | return ArgumentMatchers.isA(clazz); 222 | } 223 | 224 | /** 225 | * Delegates call to {@link ArgumentMatchers#eq(boolean)}. 226 | */ 227 | default boolean eq(boolean value) { 228 | return ArgumentMatchers.eq(value); 229 | } 230 | 231 | /** 232 | * Delegates call to {@link ArgumentMatchers#eq(byte)}. 233 | */ 234 | default byte eq(byte value) { 235 | return ArgumentMatchers.eq(value); 236 | } 237 | 238 | /** 239 | * Delegates call to {@link ArgumentMatchers#eq(char)}. 240 | */ 241 | default char eq(char value) { 242 | return ArgumentMatchers.eq(value); 243 | } 244 | 245 | /** 246 | * Delegates call to {@link ArgumentMatchers#eq(double)}. 247 | */ 248 | default double eq(double value) { 249 | return ArgumentMatchers.eq(value); 250 | } 251 | 252 | /** 253 | * Delegates call to {@link ArgumentMatchers#eq(float)}. 254 | */ 255 | default float eq(float value) { 256 | return ArgumentMatchers.eq(value); 257 | } 258 | 259 | /** 260 | * Delegates call to {@link ArgumentMatchers#eq(int)}. 261 | */ 262 | default int eq(int value) { 263 | return ArgumentMatchers.eq(value); 264 | } 265 | 266 | /** 267 | * Delegates call to {@link ArgumentMatchers#eq(long)}. 268 | */ 269 | default long eq(long value) { 270 | return ArgumentMatchers.eq(value); 271 | } 272 | 273 | /** 274 | * Delegates call to {@link ArgumentMatchers#eq(short)}. 275 | */ 276 | default short eq(short value) { 277 | return ArgumentMatchers.eq(value); 278 | } 279 | 280 | /** 281 | * Delegates call to {@link ArgumentMatchers#eq(T)}. 282 | */ 283 | default T eq(T value) { 284 | return ArgumentMatchers.eq(value); 285 | } 286 | 287 | /** 288 | * Delegates call to {@link ArgumentMatchers#refEq(T, String...)}. 289 | */ 290 | default T refEq(T value, String... excludeFields) { 291 | return ArgumentMatchers.refEq(value, excludeFields); 292 | } 293 | 294 | /** 295 | * Delegates call to {@link ArgumentMatchers#same(T)}. 296 | */ 297 | default T same(T value) { 298 | return ArgumentMatchers.same(value); 299 | } 300 | 301 | /** 302 | * Delegates call to {@link ArgumentMatchers#isNull()}. 303 | */ 304 | default T isNull() { 305 | return ArgumentMatchers.isNull(); 306 | } 307 | 308 | /** 309 | * Delegates call to {@link ArgumentMatchers#isNull(Class)}. 310 | * 311 | * @deprecated This will be removed in Mockito 3.0. 312 | */ 313 | @Deprecated 314 | default T isNull(Class clazz) { 315 | return ArgumentMatchers.isNull(clazz); 316 | } 317 | 318 | /** 319 | * Delegates call to {@link ArgumentMatchers#notNull()}. 320 | */ 321 | default T notNull() { 322 | return ArgumentMatchers.notNull(); 323 | } 324 | 325 | /** 326 | * Delegates call to {@link ArgumentMatchers#notNull(Class)}. 327 | * 328 | * @deprecated This will be removed in Mockito 3.0. 329 | */ 330 | @Deprecated 331 | default T notNull(Class clazz) { 332 | return ArgumentMatchers.notNull(clazz); 333 | } 334 | 335 | /** 336 | * Delegates call to {@link ArgumentMatchers#isNotNull()}. 337 | */ 338 | default T isNotNull() { 339 | return ArgumentMatchers.isNotNull(); 340 | } 341 | 342 | /** 343 | * Delegates call to {@link ArgumentMatchers#isNotNull(Class)}. 344 | * 345 | * @deprecated This will be removed in Mockito 3.0. 346 | */ 347 | @Deprecated 348 | default T isNotNull(Class clazz) { 349 | return ArgumentMatchers.isNotNull(clazz); 350 | } 351 | 352 | /** 353 | * Delegates call to {@link ArgumentMatchers#contains(String)}. 354 | */ 355 | default String contains(String substring) { 356 | return ArgumentMatchers.contains(substring); 357 | } 358 | 359 | /** 360 | * Delegates call to {@link ArgumentMatchers#matches(String)}. 361 | */ 362 | default String matches(String regex) { 363 | return ArgumentMatchers.matches(regex); 364 | } 365 | 366 | /** 367 | * Delegates call to {@link ArgumentMatchers#endsWith(String)}. 368 | */ 369 | default String endsWith(String suffix) { 370 | return ArgumentMatchers.endsWith(suffix); 371 | } 372 | 373 | /** 374 | * Delegates call to {@link ArgumentMatchers#startsWith(String)}. 375 | */ 376 | default String startsWith(String prefix) { 377 | return ArgumentMatchers.startsWith(prefix); 378 | } 379 | 380 | /** 381 | * Delegates call to {@link ArgumentMatchers#argThat(ArgumentMatcher)}. 382 | */ 383 | default T argThat(ArgumentMatcher matcher) { 384 | return ArgumentMatchers.argThat(matcher); 385 | } 386 | 387 | /** 388 | * Delegates call to {@link ArgumentMatchers#charThat(ArgumentMatcher)}. 389 | */ 390 | default char charThat(ArgumentMatcher matcher) { 391 | return ArgumentMatchers.charThat(matcher); 392 | } 393 | 394 | /** 395 | * Delegates call to {@link ArgumentMatchers#booleanThat(ArgumentMatcher)}. 396 | */ 397 | default boolean booleanThat(ArgumentMatcher matcher) { 398 | return ArgumentMatchers.booleanThat(matcher); 399 | } 400 | 401 | /** 402 | * Delegates call to {@link ArgumentMatchers#byteThat(ArgumentMatcher)}. 403 | */ 404 | default byte byteThat(ArgumentMatcher matcher) { 405 | return ArgumentMatchers.byteThat(matcher); 406 | } 407 | 408 | /** 409 | * Delegates call to {@link ArgumentMatchers#shortThat(ArgumentMatcher)}. 410 | */ 411 | default short shortThat(ArgumentMatcher matcher) { 412 | return ArgumentMatchers.shortThat(matcher); 413 | } 414 | 415 | /** 416 | * Delegates call to {@link ArgumentMatchers#intThat(ArgumentMatcher)}. 417 | */ 418 | default int intThat(ArgumentMatcher matcher) { 419 | return ArgumentMatchers.intThat(matcher); 420 | } 421 | 422 | /** 423 | * Delegates call to {@link ArgumentMatchers#longThat(ArgumentMatcher)}. 424 | */ 425 | default long longThat(ArgumentMatcher matcher) { 426 | return ArgumentMatchers.longThat(matcher); 427 | } 428 | 429 | /** 430 | * Delegates call to {@link ArgumentMatchers#floatThat(ArgumentMatcher)}. 431 | */ 432 | default float floatThat(ArgumentMatcher matcher) { 433 | return ArgumentMatchers.floatThat(matcher); 434 | } 435 | 436 | /** 437 | * Delegates call to {@link ArgumentMatchers#doubleThat(ArgumentMatcher)}. 438 | */ 439 | default double doubleThat(ArgumentMatcher matcher) { 440 | return ArgumentMatchers.doubleThat(matcher); 441 | } 442 | } 443 | -------------------------------------------------------------------------------- /src/main/java/info/solidsoft/mockito/java8/api/WithMockito.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Mockito contributors. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.api; 7 | 8 | import org.mockito.InOrder; 9 | import org.mockito.Incubating; 10 | import org.mockito.MockSettings; 11 | import org.mockito.MockingDetails; 12 | import org.mockito.Mockito; 13 | import org.mockito.stubbing.Answer; 14 | import org.mockito.stubbing.OngoingStubbing; 15 | import org.mockito.stubbing.Stubber; 16 | import org.mockito.verification.VerificationAfterDelay; 17 | import org.mockito.verification.VerificationMode; 18 | import org.mockito.verification.VerificationWithTimeout; 19 | 20 | /** 21 | * An entry point to classic Mockito stubbing/mocking API with basic matchers. 22 | *

23 | * Created as an alternative approach to static imports. A test class can implement that interface to make all 24 | * the methods from {@link Mockito} class directly available. 25 | * 26 | *

27 | * Sample test in Arrange-Act-Assert style: 28 | * 29 | *


 30 |  * //no static Mockito imports needed!
 31 |  *
 32 |  * class ShopTest implements WithMockito {
 33 |  *
 34 |  *   private Seller seller = mock(Seller.class);
 35 |  *   private Shop shop = new Shop(seller);
 36 |  *
 37 |  *   public void shouldBuyBread() {
 38 |  *     //arrange
 39 |  *     when(seller.askForBread()).thenReturn(new Bread());
 40 |  *     //act
 41 |  *     Goods goods = shop.buyBread();
 42 |  *     //assert
 43 |  *     assertThat(goods.containBread()).isTrue();
 44 |  *   }
 45 |  * }
 46 |  * 
47 | * 48 | * Mock verification can be then performed with {@link Mockito#verify(Object)} method: 49 | * 50 | *

 51 |  *   person.ride(bike);
 52 |  *   person.ride(bike);
 53 |  *
 54 |  *   verify(person, times(2)).ride(bike);
 55 |  *   verifyNoMoreInteractions(police);
 56 |  * 
57 | *

58 | * In many cases Behavior-driven development style may be preferred. See {@link WithBDDMockito} how it can be used 59 | * with Mockito. 60 | *

61 | * If more sophisticated matchers are needed see {@link WithAdditionalMatchers} interface. 62 | *

63 | * Based on an idea proposed by David Gageot: 64 | * http://blog.javabien.net/2014/04/23/what-if-assertj-used-java-8/ 65 | * 66 | * @see WithBDDMockito 67 | * @see WithAdditionalMatchers 68 | * 69 | * @author Marcin Zajączkowski 70 | * @since 1.0.0 71 | */ 72 | @Incubating 73 | public interface WithMockito extends WithMatchers { 74 | 75 | /** 76 | * Delegates call to {@link Mockito#mock(Class)}. 77 | */ 78 | default T mock(Class classToMock) { 79 | return Mockito.mock(classToMock); 80 | } 81 | 82 | /** 83 | * Delegates call to {@link Mockito#mock(Class, String)}. 84 | */ 85 | default T mock(Class classToMock, String name) { 86 | return Mockito.mock(classToMock, name); 87 | } 88 | 89 | /** 90 | * Delegates call to {@link Mockito#mockingDetails(Object)}. 91 | */ 92 | default MockingDetails mockingDetails(Object toInspect) { 93 | return Mockito.mockingDetails(toInspect); 94 | } 95 | 96 | /** 97 | * Delegates call to {@link Mockito#mock(Class, Answer)}. 98 | */ 99 | default T mock(Class classToMock, Answer defaultAnswer) { 100 | return Mockito.mock(classToMock, defaultAnswer); 101 | } 102 | 103 | /** 104 | * Delegates call to {@link Mockito#mock(Class, MockSettings)}. 105 | */ 106 | default T mock(Class classToMock, MockSettings mockSettings) { 107 | return Mockito.mock(classToMock, mockSettings); 108 | } 109 | 110 | /** 111 | * Delegates call to {@link Mockito#spy(Object)}. 112 | */ 113 | default T spy(T object) { 114 | return Mockito.spy(object); 115 | } 116 | 117 | /** 118 | * Delegates call to {@link Mockito#spy(Class)}. 119 | */ 120 | @Incubating 121 | default T spy(Class classToSpy) { 122 | return Mockito.spy(classToSpy); 123 | } 124 | 125 | /** 126 | * Delegates call to {@link Mockito#when(Object)}. 127 | */ 128 | default OngoingStubbing when(T methodCall) { 129 | return Mockito.when(methodCall); 130 | } 131 | 132 | /** 133 | * Delegates call to {@link Mockito#verify(Object)}. 134 | */ 135 | default T verify(T mock) { 136 | return Mockito.verify(mock, times(1)); 137 | } 138 | 139 | /** 140 | * Delegates call to {@link Mockito#verify(Object, VerificationMode)}. 141 | */ 142 | default T verify(T mock, VerificationMode mode) { 143 | return Mockito.verify(mock, mode); 144 | } 145 | 146 | /** 147 | * Delegates call to {@link Mockito#reset(Object[])}. 148 | */ 149 | default void reset(T ... mocks) { 150 | Mockito.reset(mocks); 151 | } 152 | 153 | /** 154 | * Delegates call to {@link Mockito#verifyNoMoreInteractions(Object...)}. 155 | */ 156 | default void verifyNoMoreInteractions(Object... mocks) { 157 | Mockito.verifyNoMoreInteractions(mocks); 158 | } 159 | 160 | /** 161 | * Delegates call to {@link Mockito#verifyZeroInteractions(Object...)}. 162 | */ 163 | default void verifyZeroInteractions(Object... mocks) { 164 | Mockito.verifyNoMoreInteractions(mocks); 165 | } 166 | 167 | /** 168 | * Delegates call to {@link Mockito#doThrow(Throwable...)}. 169 | */ 170 | default Stubber doThrow(Throwable... toBeThrown) { 171 | return Mockito.doThrow(toBeThrown); 172 | } 173 | 174 | /** 175 | * Delegates call to {@link Mockito#doThrow(Class)}. 176 | */ 177 | default Stubber doThrow(Class toBeThrown) { 178 | return Mockito.doThrow(toBeThrown); 179 | } 180 | 181 | /** 182 | * Delegates call to {@link Mockito#doCallRealMethod()}. 183 | */ 184 | default Stubber doCallRealMethod() { 185 | return Mockito.doCallRealMethod(); 186 | } 187 | 188 | /** 189 | * Delegates call to {@link Mockito#doAnswer(Answer)}. 190 | */ 191 | default Stubber doAnswer(Answer answer) { 192 | return Mockito.doAnswer(answer); 193 | } 194 | 195 | /** 196 | * Delegates call to {@link Mockito#doNothing()}. 197 | */ 198 | default Stubber doNothing() { 199 | return Mockito.doNothing(); 200 | } 201 | 202 | /** 203 | * Delegates call to {@link Mockito#doReturn(Object)}. 204 | */ 205 | default Stubber doReturn(Object toBeReturned) { 206 | return Mockito.doReturn(toBeReturned); 207 | } 208 | 209 | /** 210 | * Delegates call to {@link Mockito#doReturn(Object, Object...)}. 211 | */ 212 | default Stubber doReturn(Object toBeReturned, Object... toBeReturnedNext) { 213 | return Mockito.doReturn(toBeReturned, toBeReturnedNext); 214 | } 215 | 216 | /** 217 | * Delegates call to {@link Mockito#inOrder(Object...)}. 218 | */ 219 | default InOrder inOrder(Object... mocks) { 220 | return Mockito.inOrder(mocks); 221 | } 222 | 223 | /** 224 | * Delegates call to {@link Mockito#ignoreStubs(Object...)}. 225 | */ 226 | default Object[] ignoreStubs(Object... mocks) { 227 | return Mockito.ignoreStubs(mocks); 228 | } 229 | 230 | /** 231 | * Delegates call to {@link Mockito#times(int)}. 232 | */ 233 | default VerificationMode times(int wantedNumberOfInvocations) { 234 | return Mockito.times(wantedNumberOfInvocations); 235 | } 236 | 237 | /** 238 | * Delegates call to {@link Mockito#never()}. 239 | */ 240 | default VerificationMode never() { 241 | return Mockito.never(); 242 | } 243 | 244 | /** 245 | * Delegates call to {@link Mockito#atLeastOnce()}. 246 | */ 247 | default VerificationMode atLeastOnce() { 248 | return Mockito.atLeastOnce(); 249 | } 250 | 251 | /** 252 | * Delegates call to {@link Mockito#atLeast(int)}. 253 | */ 254 | default VerificationMode atLeast(int minNumberOfInvocations) { 255 | return Mockito.atLeast(minNumberOfInvocations); 256 | } 257 | 258 | /** 259 | * Delegates call to {@link Mockito#atMost(int)}. 260 | */ 261 | default VerificationMode atMost(int maxNumberOfInvocations) { 262 | return Mockito.atMost(maxNumberOfInvocations); 263 | } 264 | 265 | /** 266 | * Delegates call to {@link Mockito#calls(int)}. 267 | */ 268 | default VerificationMode calls(int wantedNumberOfInvocations){ 269 | return Mockito.calls(wantedNumberOfInvocations); 270 | } 271 | 272 | /** 273 | * Delegates call to {@link Mockito#only()}. 274 | */ 275 | default VerificationMode only() { 276 | return Mockito.only(); 277 | } 278 | 279 | /** 280 | * Delegates call to {@link Mockito#timeout(long)}. 281 | */ 282 | default VerificationWithTimeout timeout(long millis) { 283 | return Mockito.timeout(millis); 284 | } 285 | 286 | /** 287 | * Delegates call to {@link Mockito#after(long)}. 288 | */ 289 | default VerificationAfterDelay after(long millis) { 290 | return Mockito.after(millis); 291 | } 292 | 293 | /** 294 | * Delegates call to {@link Mockito#validateMockitoUsage()}. 295 | */ 296 | default void validateMockitoUsage() { 297 | Mockito.validateMockitoUsage(); 298 | } 299 | 300 | /** 301 | * Delegates call to {@link Mockito#withSettings()}. 302 | */ 303 | default MockSettings withSettings() { 304 | return Mockito.withSettings(); 305 | } 306 | 307 | /** 308 | * Delegates call to {@link Mockito#description(String)}. 309 | * 310 | * @since 2.0.0 311 | */ 312 | default VerificationMode description(String description) { 313 | return Mockito.description(description); 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/AssertionMatcherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8; 7 | 8 | import info.solidsoft.mockito.java8.domain.ShipSearchCriteria; 9 | import info.solidsoft.mockito.java8.domain.TacticalStation; 10 | import org.assertj.core.api.ThrowableAssert; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.extension.ExtendWith; 13 | import org.mockito.ArgumentCaptor; 14 | import org.mockito.Mock; 15 | import org.mockito.junit.jupiter.MockitoExtension; 16 | 17 | import java.io.IOException; 18 | 19 | import static info.solidsoft.mockito.java8.AssertionMatcher.assertArg; 20 | import static info.solidsoft.mockito.java8.AssertionMatcher.assertArgThrowing; 21 | import static org.assertj.core.api.Assertions.assertThat; 22 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 23 | import static org.mockito.Mockito.verify; 24 | 25 | @ExtendWith(MockitoExtension.class) 26 | class AssertionMatcherTest { 27 | 28 | @Mock 29 | private TacticalStation ts; 30 | 31 | private ShipSearchCriteria searchCriteria = new ShipSearchCriteria(1000, 4); 32 | 33 | @Test 34 | void shouldAllowToUseArgumentCaptorInClassicWay() { 35 | //when 36 | ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 37 | //then 38 | ArgumentCaptor captor = ArgumentCaptor.forClass(ShipSearchCriteria.class); 39 | verify(ts).findNumberOfShipsInRangeByCriteria(captor.capture()); 40 | assertThat(captor.getValue().getMinimumRange()).isLessThan(2000); 41 | } 42 | 43 | @Test 44 | void shouldAllowToUseAssertionInLambda() { 45 | //when 46 | ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 47 | //then 48 | verify(ts).findNumberOfShipsInRangeByCriteria(assertArg(sc -> assertThat(sc.getMinimumRange()).isLessThan(2000))); 49 | } 50 | 51 | @Test 52 | void shouldAllowToUseAssertionInLambdaWithPrimitiveAsArgument() { 53 | //when 54 | ts.fireTorpedo(2); 55 | //then 56 | verify(ts).fireTorpedo(assertArg(i -> assertThat(i).isEqualTo(2))); 57 | } 58 | 59 | @Test 60 | void shouldHaveMeaningfulErrorMessage() { 61 | //when 62 | ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 63 | //then 64 | ThrowableAssert.ThrowingCallable verifyLambda = () -> { 65 | verify(ts).findNumberOfShipsInRangeByCriteria(assertArg(sc -> assertThat(sc.getMinimumRange()).isLessThan(50))); 66 | }; 67 | assertThatThrownBy(verifyLambda) 68 | .isInstanceOf(AssertionError.class) 69 | .hasMessageContaining("Argument(s) are different! Wanted:\n" + 70 | "ts.findNumberOfShipsInRangeByCriteria(\n" + 71 | " AssertionMatcher reported: \n" + 72 | "Expecting:\n" + 73 | " <1000>\n" + 74 | "to be less than:\n" + 75 | " <50> ") 76 | .hasMessageContaining("Actual invocation has different arguments:\n" + 77 | "ts.findNumberOfShipsInRangeByCriteria(\n" + 78 | " ShipSearchCriteria{minimumRange=1000, numberOfPhasers=4}\n" + 79 | ");"); 80 | } 81 | 82 | @SuppressWarnings("Convert2MethodRef") 83 | @Test 84 | void shouldAcceptLambdaWhichMayThrowCheckedException() { 85 | //when 86 | ts.fireTorpedo(2); 87 | //then 88 | verify(ts).fireTorpedo(assertArgThrowing(i -> methodDeclaringThrowingCheckedException(i))); 89 | } 90 | 91 | @Test 92 | void shouldAcceptMethodReferenceWhichMayThrowCheckedException() { 93 | //when 94 | ts.fireTorpedo(2); 95 | //then 96 | verify(ts).fireTorpedo(assertArgThrowing(this::methodDeclaringThrowingCheckedException)); 97 | } 98 | 99 | @Test 100 | void shouldPropagateCheckedExceptionIfThrownInLambda() { 101 | //when 102 | ts.fireTorpedo(2); 103 | //then 104 | assertThatThrownBy(() -> verify(ts).fireTorpedo(assertArgThrowing(i -> { 105 | throw new IOException("Unexpected checked exception"); 106 | }))) 107 | .isInstanceOf(IOException.class); 108 | } 109 | 110 | private void methodDeclaringThrowingCheckedException(int i) throws Exception { 111 | assertThat(i).isEqualTo(2); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/LambdaMatcherStubbingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8; 7 | 8 | import info.solidsoft.mockito.java8.domain.ShipSearchCriteria; 9 | import info.solidsoft.mockito.java8.domain.TacticalStation; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.mockito.Mock; 13 | import org.mockito.invocation.InvocationOnMock; 14 | import org.mockito.junit.jupiter.MockitoExtension; 15 | import org.mockito.stubbing.Answer; 16 | 17 | import static info.solidsoft.mockito.java8.LambdaMatcher.argLambda; 18 | import static org.assertj.core.api.Assertions.assertThat; 19 | import static org.mockito.ArgumentMatchers.any; 20 | import static org.mockito.BDDMockito.given; 21 | 22 | @ExtendWith(MockitoExtension.class) 23 | class LambdaMatcherStubbingTest { 24 | 25 | @Mock 26 | private TacticalStation ts; 27 | 28 | @Test 29 | void shouldAllowToUseLambdaInStubbing() { 30 | //given 31 | given(ts.findNumberOfShipsInRangeByCriteria(argLambda(c -> c.getMinimumRange() > 1000))).willReturn(4); 32 | //expect 33 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))).isEqualTo(4); 34 | //expect 35 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))).isEqualTo(0); 36 | } 37 | 38 | @SuppressWarnings("Convert2Lambda") 39 | @Test 40 | void stubbingWithCustomAnswerShouldBeLonger() { 41 | //given 42 | given(ts.findNumberOfShipsInRangeByCriteria(any())).willAnswer(new Answer() { 43 | @Override 44 | public Integer answer(InvocationOnMock invocation) throws Throwable { 45 | Object[] args = invocation.getArguments(); 46 | ShipSearchCriteria criteria = (ShipSearchCriteria) args[0]; 47 | if (criteria.getMinimumRange() > 1000) { 48 | return 4; 49 | } else { 50 | return 0; 51 | } 52 | } 53 | }); 54 | //expect 55 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))).isEqualTo(4); 56 | //expect 57 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))).isEqualTo(0); 58 | } 59 | 60 | @Test 61 | void stubbingWithCustomAnswerShouldBeLongerEvenAsLambda() { 62 | //given 63 | given(ts.findNumberOfShipsInRangeByCriteria(any())).willAnswer(invocation -> { 64 | ShipSearchCriteria criteria = (ShipSearchCriteria) invocation.getArguments()[0]; 65 | return criteria.getMinimumRange() > 1000 ? 4 : 0; 66 | }); 67 | //expect 68 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(1500, 2))).isEqualTo(4); 69 | //expect 70 | assertThat(ts.findNumberOfShipsInRangeByCriteria(new ShipSearchCriteria(700, 2))).isEqualTo(0); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/LambdaMatcherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8; 7 | 8 | import info.solidsoft.mockito.java8.domain.ShipSearchCriteria; 9 | import info.solidsoft.mockito.java8.domain.TacticalStation; 10 | import org.assertj.core.api.ThrowableAssert; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.extension.ExtendWith; 13 | import org.mockito.ArgumentMatcher; 14 | import org.mockito.Mock; 15 | import org.mockito.junit.jupiter.MockitoExtension; 16 | 17 | import java.io.IOException; 18 | 19 | import static info.solidsoft.mockito.java8.LambdaMatcher.argLambda; 20 | import static info.solidsoft.mockito.java8.LambdaMatcher.argLambdaThrowing; 21 | import static org.assertj.core.api.Assertions.assertThat; 22 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 23 | import static org.mockito.ArgumentMatchers.argThat; 24 | import static org.mockito.Mockito.verify; 25 | 26 | @ExtendWith(MockitoExtension.class) 27 | class LambdaMatcherTest { 28 | 29 | private static final String UNEXPECTED_CHECKED_EXCEPTION_MESSAGE = "Unexpected checked exception"; 30 | 31 | @Mock 32 | private TacticalStation ts; 33 | 34 | private ShipSearchCriteria searchCriteria = new ShipSearchCriteria(1000, 4); 35 | 36 | @Test 37 | void simpleBaseMatcherShouldWork() { 38 | //when 39 | int numberOfShips = ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 40 | //then 41 | assertThat(numberOfShips).isZero(); 42 | //and 43 | verify(ts).findNumberOfShipsInRangeByCriteria(argThat(new ArgumentMatcher() { 44 | @Override 45 | public boolean matches(ShipSearchCriteria criteria) { 46 | return criteria.getMinimumRange() < 2000 && criteria.getNumberOfPhasers() > 2; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "ShipSearchCriteria minimumRange<2000 and numberOfPhasers>2"; 52 | } 53 | })); 54 | } 55 | 56 | /* 57 | //Only as comparison - Hamcrest matchers are no longer on project classpath 58 | @Test 59 | void customMatcherShouldBeMoreCompact() { 60 | //when 61 | int numberOfShips = ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 62 | //then 63 | assertThat(numberOfShips).isZero(); 64 | //and 65 | verify(ts).findNumberOfShipsInRangeByCriteria(argThat(new HamcrestArgumentMatcher<>( 66 | new CustomMatcher("ShipSearchCriteria minimumRange<2000 and numberOfPhasers>2") { 67 | @Override 68 | public boolean matches(Object item) { 69 | ShipSearchCriteria criteria = (ShipSearchCriteria) item; 70 | return criteria.getMinimumRange() < 2000 && criteria.getNumberOfPhasers() > 2; 71 | } 72 | }))); 73 | } 74 | */ 75 | 76 | @Test 77 | void argumentMatcherShouldBeEvenMoreCompact() { 78 | //when 79 | int numberOfShips = ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 80 | //then 81 | assertThat(numberOfShips).isZero(); 82 | //and 83 | verify(ts).findNumberOfShipsInRangeByCriteria(argThat(new MoreThan2ShipsCloserThan2000())); 84 | } 85 | 86 | //TODO: 2000 -> 2 0 0 0 - useful anywhere? - worth to implement? 87 | private static class MoreThan2ShipsCloserThan2000 implements ArgumentMatcher { 88 | @Override 89 | public boolean matches(ShipSearchCriteria criteria) { 90 | return criteria.getMinimumRange() < 2000 && criteria.getNumberOfPhasers() > 2; 91 | } 92 | } 93 | 94 | @Test 95 | void shouldAllowToUseLambdaInMatcher() { 96 | //when 97 | int numberOfShips = ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 98 | //then 99 | assertThat(numberOfShips).isZero(); 100 | //and 101 | verify(ts).findNumberOfShipsInRangeByCriteria(argLambda(c -> c.getMinimumRange() < 2000)); 102 | } 103 | 104 | @Test 105 | void shouldAllowToUseLambdaInMatcherWithAdditionalDescription() { 106 | //when 107 | int numberOfShips = ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 108 | //then 109 | assertThat(numberOfShips).isZero(); 110 | //and 111 | verify(ts).findNumberOfShipsInRangeByCriteria(argLambda(c -> c.getMinimumRange() < 2000, "minimum range closer than 2000")); 112 | } 113 | 114 | @Test 115 | void shouldAllowToUseLambdaWithMultipleConditionsInMatcher() { 116 | //when 117 | int numberOfShips = ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 118 | //then 119 | assertThat(numberOfShips).isZero(); 120 | //and 121 | verify(ts).findNumberOfShipsInRangeByCriteria(argLambda( 122 | c -> c.getMinimumRange() < 2000 && c.getNumberOfPhasers() > 2, 123 | "ShipSearchCriteria minimumRange<2000 and numberOfPhasers>2")); 124 | } 125 | 126 | @Test 127 | void shouldKeepDescriptionInErrorMessage() { 128 | //given 129 | final String DESCRIPTION = "minimum range closer than 100"; 130 | //when 131 | ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 132 | //then 133 | ThrowableAssert.ThrowingCallable verifyLambda = () -> { 134 | verify(ts).findNumberOfShipsInRangeByCriteria(argLambda(c -> c.getMinimumRange() < 100, DESCRIPTION)); 135 | }; 136 | assertThatThrownBy(verifyLambda) 137 | .isInstanceOf(AssertionError.class) 138 | .hasMessageContaining("Argument(s) are different! Wanted:\n" + 139 | "ts.findNumberOfShipsInRangeByCriteria(\n" + 140 | " " + DESCRIPTION + "\n" + 141 | ");") 142 | .hasMessageContaining("Actual invocation has different arguments:\n" + 143 | "ts.findNumberOfShipsInRangeByCriteria(\n" + 144 | " ShipSearchCriteria{minimumRange=1000, numberOfPhasers=4}\n" + 145 | ");"); 146 | 147 | } 148 | 149 | @Test 150 | void shouldAcceptLambdaWhichMayThrowCheckedException() throws Exception { 151 | //when 152 | int numberOfShips = ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 153 | //then 154 | assertThat(numberOfShips).isZero(); 155 | //and 156 | verify(ts).findNumberOfShipsInRangeByCriteria(argLambdaThrowing(methodDeclaringThrowingCheckedException())); 157 | } 158 | 159 | @Test 160 | void shouldPropagateCheckedExceptionIfThrownInLambda() throws Exception { 161 | //when 162 | int numberOfShips = ts.findNumberOfShipsInRangeByCriteria(searchCriteria); 163 | //then 164 | assertThat(numberOfShips).isZero(); 165 | //and 166 | assertThatThrownBy(() -> verify(ts).findNumberOfShipsInRangeByCriteria(argLambdaThrowing(c -> { 167 | throw new IOException(UNEXPECTED_CHECKED_EXCEPTION_MESSAGE); 168 | }))) 169 | .isInstanceOf(RuntimeException.class) 170 | .hasCauseInstanceOf(IOException.class) 171 | .hasMessage("java.io.IOException: " + UNEXPECTED_CHECKED_EXCEPTION_MESSAGE); 172 | } 173 | 174 | @SuppressWarnings("RedundantThrows") 175 | private ThrowingPredicate methodDeclaringThrowingCheckedException() throws Exception { 176 | return c -> c.getMinimumRange() < 2000 && c.getNumberOfPhasers() > 2; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/api/WithBDDMockitoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.api; 7 | 8 | import info.solidsoft.mockito.java8.domain.TacticalStation; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import java.io.BufferedWriter; 12 | import java.io.IOException; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 16 | 17 | class WithBDDMockitoTest implements WithBDDMockito { 18 | 19 | @Test 20 | void shouldAllowToCreateMockAndStubWithAnswerInClassicStyleWithoutStaticImports() { 21 | //given 22 | TacticalStation tsMock = mock(TacticalStation.class); 23 | given(tsMock.getNumberOfTubes()).willAnswer(i -> 3); 24 | //when 25 | int numberOfTubes = tsMock.getNumberOfTubes(); 26 | //then 27 | assertThat(numberOfTubes).isEqualTo(3); 28 | } 29 | 30 | @Test 31 | void shouldVerifyMethodExecutionWithBasicMatcherWithoutStaticImports() { 32 | //given 33 | TacticalStation tsSpy = spy(TacticalStation.class); 34 | willDoNothing().given(tsSpy).fireTorpedo(anyInt()); 35 | //when 36 | tsSpy.fireTorpedo(2); 37 | tsSpy.fireTorpedo(2); 38 | //then 39 | then(tsSpy).should(times(2)).fireTorpedo(2); 40 | } 41 | 42 | @Test //Issue #7 43 | void shouldProperlyCallVarargsMethod() throws IOException { 44 | //given 45 | BufferedWriter writerMock = mock(BufferedWriter.class); 46 | //when 47 | willThrow(new IOException()).given(writerMock).write(anyString()); 48 | //then 49 | assertThatThrownBy(() -> writerMock.write("should throw IOException")) 50 | .isInstanceOf(IOException.class); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/api/WithMockitoAndAdditionalMatchersTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.api; 7 | 8 | import info.solidsoft.mockito.java8.domain.TacticalStation; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import static info.solidsoft.mockito.java8.domain.TacticalStation.TubeStatus.LOADED; 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | class WithMockitoAndAdditionalMatchersTest implements WithBDDMockito, WithAdditionalMatchers { 15 | 16 | @Test 17 | void shouldAllowToCreateSpyStubAndVerifyWithMatcherWithoutStaticImports() { 18 | //given 19 | TacticalStation tsSpy = spy(TacticalStation.class); 20 | willDoNothing().given(tsSpy).fireTorpedo(lt(3)); 21 | //when 22 | tsSpy.fireTorpedo(2); 23 | //then 24 | verify(tsSpy, atLeastOnce()).fireTorpedo(2); 25 | } 26 | 27 | @Test 28 | void shouldAllowToCreateMockAndStubWithoutStaticImports() { 29 | //given 30 | TacticalStation tsMock = mock(TacticalStation.class); 31 | given(tsMock.getTubeStatus(geq(2))).willReturn(LOADED); 32 | //when 33 | TacticalStation.TubeStatus numberOfTubes = tsMock.getTubeStatus(2); 34 | //then 35 | assertThat(numberOfTubes).isEqualTo(LOADED); 36 | } 37 | 38 | @Test 39 | void shouldVerifyMethodExecutionToAdditionalMatcherWithoutStaticImports() { 40 | //given 41 | TacticalStation tsSpy = spy(TacticalStation.class); 42 | willDoNothing().given(tsSpy).fireTorpedo(2); 43 | //when 44 | tsSpy.fireTorpedo(2); 45 | tsSpy.fireTorpedo(2); 46 | //then 47 | then(tsSpy).should(times(2)).fireTorpedo(and(gt(1), lt(3))); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/api/WithMockitoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.api; 7 | 8 | import info.solidsoft.mockito.java8.domain.TacticalStation; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | 13 | class WithMockitoTest implements WithMockito { 14 | 15 | @Test 16 | void shouldVerifyMethodExecution() { 17 | //arrange 18 | TacticalStation tsSpy = spy(TacticalStation.class); 19 | doNothing().when(tsSpy).fireTorpedo(2); 20 | //act 21 | tsSpy.fireTorpedo(2); 22 | tsSpy.fireTorpedo(2); 23 | //assert 24 | verify(tsSpy, times(2)).fireTorpedo(2); 25 | } 26 | 27 | @Test 28 | void shouldAllowToCreateMockAndStubWithAnswerInClassicStyleWithoutStaticImports() { 29 | //arrange 30 | TacticalStation tsMock = mock(TacticalStation.class); 31 | when(tsMock.getNumberOfTubes()).thenAnswer(i -> 3); 32 | //act 33 | int numberOfTubes = tsMock.getNumberOfTubes(); 34 | //assert 35 | assertThat(numberOfTubes).isEqualTo(3); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/domain/ShipSearchCriteria.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.domain; 7 | 8 | /** 9 | * Test domain classes. 10 | */ 11 | public class ShipSearchCriteria { 12 | 13 | private final int minimumRange; 14 | private final int numberOfPhasers; 15 | 16 | public ShipSearchCriteria(int minimumRange, int numberOfPhasers) { 17 | this.minimumRange = minimumRange; 18 | this.numberOfPhasers = numberOfPhasers; 19 | } 20 | 21 | public int getMinimumRange() { 22 | return minimumRange; 23 | } 24 | 25 | public int getNumberOfPhasers() { 26 | return numberOfPhasers; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "ShipSearchCriteria{" + 32 | "minimumRange=" + minimumRange + 33 | ", numberOfPhasers=" + numberOfPhasers + 34 | '}'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/domain/TacticalStation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.domain; 7 | 8 | /** 9 | * Test domain classes. 10 | */ 11 | public class TacticalStation { 12 | 13 | public enum TubeStatus { 14 | EMPTY, LOADING, LOADED, UNLOADING, BROKEN 15 | } 16 | 17 | public int getNumberOfEnemyShipsInRange() { 18 | return 0; 19 | } 20 | 21 | public void fireTorpedo() { 22 | fireTorpedo(getNumberOfFirstLoadedTube()); 23 | } 24 | 25 | public void fireTorpedo(int tubeNumber) { 26 | } 27 | 28 | private int getNumberOfFirstLoadedTube() { 29 | return 0; 30 | } 31 | 32 | public int getNumberOfTubes() { 33 | return 0; 34 | } 35 | 36 | public void reloadTubeWithGivenTorpedoType(int tubeNumber, TopedoType topedoType) { 37 | } 38 | 39 | public int getNumberOfRemainingTorpedos() { 40 | return 0; 41 | } 42 | 43 | public TubeStatus getTubeStatus(int tubeNumber) { 44 | return null; 45 | } 46 | 47 | public int smellyFindNumberOfShipsInRangeByCriteria(int minimumRange, String partOfName, int numberOfPhasers) { 48 | return 0; 49 | } 50 | 51 | public int findNumberOfShipsInRangeByCriteria(ShipSearchCriteria searchCriteria) { 52 | return 0; 53 | } 54 | 55 | public void firePhaser() { 56 | } 57 | 58 | public void doSelfCheck() { 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/info/solidsoft/mockito/java8/domain/TopedoType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Marcin Zajączkowski. 3 | * 4 | * Licensed under the Apache License, Version 2.0. 5 | */ 6 | package info.solidsoft.mockito.java8.domain; 7 | 8 | /** 9 | * Test domain classes. 10 | */ 11 | public enum TopedoType { 12 | PHOTON, CHRONITRON, PLASMA, QUANTUM 13 | } 14 | --------------------------------------------------------------------------------