Java: port java/mocking-all-non-private-methods-means-unit-test-is-too-big query

This commit is contained in:
Napalys Klicius
2025-08-11 10:36:02 +02:00
parent 9905cd6436
commit 50c7160819
27 changed files with 1325 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
# J-T-001: Mocking all non-private methods of a class may indicate the unit test is testing too much
Mocking too many non-private methods of a class may indicate that the test is too complicated, possibly because it is trying to test multiple things at once.
## Overview
Mocking methods of a class is necessary for a unit test to run without overhead caused by expensive I/O operations necessary to compute their values. However, if a unit test ends up mocking all of them, it is likely a signal that the scope of the unit test is reaching beyond a single unit of functionality.
## Recommendation
It is best to contain the scope of a single unit test to a single unit of functionality. For example, a unit test may aim to test a series of data-transforming functions that depends on an ORM class. Even though the functions may be semantically related with one another, it is better to create a unit test for each function.
## Example
The following example mocks all methods of an ORM class named `EmployeeRecord`, and tests four functions against them. Since the scope of the unit test harbors all four of them, all of the methods provided by the class are mocked.
```java
public class EmployeeRecord {
public int add(Employee employee) { ... }
public Employee get(String name) { ... }
public int update(Employee employee, String newName) { ... }
public int delete(Employee employee) { ... }
}
public class TestORM {
@Test
public void nonCompliant() {
Employee sampleEmployee = new Employee("John Doe");
EmployeeRecord employeeRecordMock = mock(EmployeeRecord.class); // NON_COMPLIANT: Mocked class has all of its public methods used in the test
when(employeeRecordMock.add(Employee.class)).thenReturn(0); // Mocked EmployeeRecord.add
when(employeeRecordMock.get(String.class)).thenReturn(sampleEmployee); // Mocked EmployeeRecord.get
when(employeeRecordMock.update(Employee.class, String.class)).thenReturn(0); // Mocked EmployeeRecord.update
when(employeeRecordMock.delete(Employee.class)).thenReturn(0); // Mocked EmployeeRecord.delete
}
@Test
public void compliant1() {
Employee sampleEmployee = new Employee("John Doe");
EmployeeRecord employeeRecordMock = mock(EmployeeRecord.class); // COMPLIANT: Only some of the public methods belonging to the mocked object are used
when(employeeRecordMock.add(sampleEmployee)).thenReturn(0); // Mocked EmployeeRecord.add
when(employeeRecordMock.update(sampleEmployee, "Jane Doe")).thenReturn(0); // Mocked EmployeeRecord.update
}
}
```
## Implementation Notes
JUnit provides two different ways of mocking a method call: `when(mockedObject.methodToMock(...)).thenReturn(...)` and `doReturn(...).when(mockedObject).methodToMock(...)`. Both forms are taken into account by the query.
## References
- Baeldung: [Best Practices for Unit Testing in Java](https://www.baeldung.com/java-unit-testing-best-practices).

View File

@@ -0,0 +1,73 @@
/**
* @id java/mocking-all-non-private-methods-means-unit-test-is-too-big
* @name J-T-001: Mocking all non-private methods of a class may indicate the unit test is testing too much
* @description Mocking all non-private methods provided by a class might indicate the unit test
* aims to test too many things.
* @kind problem
* @precision high
* @problem.severity recommendation
* @tags maintainability
* readability
*/
import java
class MockitoMockCall extends MethodCall {
MockitoMockCall() { this.getMethod().hasQualifiedName("org.mockito", "Mockito", "mock") }
/**
* Gets the type that this call intends to mock. e.g.
* ``` java
* EmployeeRecord employeeRecordMock = mock(EmployeeRecord.class);
* ```
* This predicate gets the class `EmployeeRecord` in the above example.
*/
Type getMockedType() { result = this.getAnArgument().(TypeLiteral).getReferencedType() }
}
/**
* A method call that mocks a target method in a JUnit test. e.g.
* ``` java
* EmployeeRecord employeeRecordMock = mock(EmployeeRecord.class);
* when(employeeRecordMock.add(sampleEmployee)).thenReturn(0); // Mocked EmployeeRecord.add
* doReturn(0).when(employeeRecordMock).add(sampleEmployee); // Mocked EmployeeRecord.add
* ```
* This class captures the call to `add` which mocks the equivalent method of the class `EmployeeRecord`.
*/
class MockitoMockingMethodCall extends MethodCall {
MockitoMockCall mockCall;
MockitoMockingMethodCall() {
/* 1. The qualifier originates from the mock call. */
this.getQualifier().getControlFlowNode().getAPredecessor+() = mockCall.getControlFlowNode() and
/* 2. The mocked method can be found in the class being mocked with the mock call. */
mockCall.getMockedType().(ClassOrInterface).getAMethod() = this.getMethod()
}
/**
* Gets the call to Mockito's `mock` from which the qualifier, the mocked object, originates.
*/
MockitoMockCall getMockitoMockCall() { result = mockCall }
}
/*
* The following from-which-select embodies this pseudocode:
* - Find a JUnit4TestMethod which:
* - for a class that it mocks with a call to `mock`,
* - for all methods that the class has, there is a method that this test method mocks.
*/
from JUnit4TestMethod testMethod, ClassOrInterface mockedClassOrInterface
where
exists(MockitoMockCall mockCall |
mockCall.getParent+().(Stmt) = testMethod.getBody().getAStmt() and
mockedClassOrInterface = mockCall.getMockedType() and
forex(Method method | method = mockedClassOrInterface.getAMethod() and method.isPublic() |
exists(MockitoMockingMethodCall mockedMethod |
mockedMethod.getMockitoMockCall() = mockCall and
mockedMethod.getMethod() = method
)
)
)
select testMethod, "This test method mocks all public methods of a $@.", mockedClassOrInterface,
"class or an interface"

View File

@@ -0,0 +1,10 @@
/**
* Underlying data type of the ORM class and functions.
*/
public class Employee {
Employee(String name) {
this.name = name;
}
String name;
}

View File

@@ -0,0 +1,26 @@
/**
* Sample ORM class for the type `Employee`.
*/
public class EmployeeRecord {
public int add(Employee employee) {
return 1;
}
public Employee get(String name) {
return new Employee("Sample");
}
public int update(Employee employee, String newName) {
return 1;
}
public int delete(Employee employee) {
return 1;
}
private void f() { }
private void g() { }
private void h() { }
}

View File

@@ -0,0 +1,2 @@
| TestORM.java:34:15:34:27 | nonCompliant1 | This test method mocks all public methods of a $@. | EmployeeRecord.java:4:14:4:27 | EmployeeRecord | class or an interface |
| TestORM.java:47:15:47:27 | nonCompliant2 | This test method mocks all public methods of a $@. | EmployeeRecord.java:4:14:4:27 | EmployeeRecord | class or an interface |

View File

@@ -0,0 +1 @@
Likely Bugs/Frameworks/JUnit/MockingAllNonPrivateMethodsMeansUnitTestIsTooBig.ql

View File

@@ -0,0 +1,55 @@
import org.junit.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.doReturn;
public class TestORM {
/**
* Test of form `when(mockedObject.methodToBeMocked()).thenReturn(someVal)`.
*/
@Test
public void compliant1() {
Employee sampleEmployee = new Employee("John Doe");
EmployeeRecord employeeRecordMock = mock(EmployeeRecord.class); // COMPLIANT: Only some of the public methods belonging to the mocked object are used
when(employeeRecordMock.add(sampleEmployee)).thenReturn(0); // Mocked EmployeeRecord.add
when(employeeRecordMock.update(sampleEmployee, "Jane Doe")).thenReturn(0); // Mocked EmployeeRecord.update
}
/**
* Test of form `doReturn(someVal).when(mockedObject).methodToBeMocked()`.
*/
@Test
public void compliant2() {
Employee sampleEmployee = new Employee("John Doe");
EmployeeRecord employeeRecordMock = mock(EmployeeRecord.class); // COMPLIANT: Only some of the public methods belonging to the mocked object are used
doReturn(0).when(employeeRecordMock).add(sampleEmployee); // Mocked EmployeeRecord.add
doReturn(0).when(employeeRecordMock).get("John Doe"); // Mocked EmployeeRecord.get
doReturn(0).when(employeeRecordMock).delete(sampleEmployee); // Mocked EmployeeRecord.delete
}
/**
* Test of form `when(mockedObject.methodToBeMocked()).thenReturn(someVal)`.
*/
@Test
public void nonCompliant1() {
Employee sampleEmployee = new Employee("John Doe");
EmployeeRecord employeeRecordMock = mock(EmployeeRecord.class); // NON_COMPLIANT: All public methods of the mocked object are used
when(employeeRecordMock.add(sampleEmployee)).thenReturn(0); // Mocked EmployeeRecord.add
when(employeeRecordMock.get("John Doe")).thenReturn(sampleEmployee); // Mocked EmployeeRecord.get
when(employeeRecordMock.update(sampleEmployee, "Jane Doe")).thenReturn(0); // Mocked EmployeeRecord.update
when(employeeRecordMock.delete(sampleEmployee)).thenReturn(0); // Mocked EmployeeRecord.delete
}
/**
* Test of form `doReturn(someVal).when(mockedObject).methodToBeMocked()`.
*/
@Test
public void nonCompliant2() {
Employee sampleEmployee = new Employee("John Doe");
EmployeeRecord employeeRecordMock = mock(EmployeeRecord.class); // NON_COMPLIANT: All public methods of the mocked object are used
doReturn(0).when(employeeRecordMock).add(sampleEmployee); // Mocked EmployeeRecord.add
doReturn(0).when(employeeRecordMock).get("John Doe"); // Mocked EmployeeRecord.get
doReturn(0).when(employeeRecordMock).update(sampleEmployee, "Jane Doe"); // Mocked EmployeeRecord.update
doReturn(0).when(employeeRecordMock).delete(sampleEmployee); // Mocked EmployeeRecord.delete
}
}

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/junit-4.13:${testdir}/../../stubs/mockito-5.14

View File

@@ -0,0 +1,214 @@
JUnit
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial code and
documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and are
distributed by that particular Contributor. A Contribution 'originates' from a
Contributor if it was added to the Program by such Contributor itself or anyone
acting on such Contributor's behalf. Contributions do not include additions to
the Program which: (i) are separate modules of software distributed in
conjunction with the Program under their own license agreement, and (ii) are
not derivative works of the Program.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents " mean patent claims licensable by a Contributor which are
necessarily infringed by the use or sale of its Contribution alone or when
combined with the Program.
"Program" means the Contributions distributed in accordance with this Agreement.
"Recipient" means anyone who receives the Program under this Agreement,
including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide, royalty-free copyright license to
reproduce, prepare derivative works of, publicly display, publicly perform,
distribute and sublicense the Contribution of such Contributor, if any, and
such derivative works, in source code and object code form.
b) Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide, royalty-free patent license under
Licensed Patents to make, use, sell, offer to sell, import and otherwise
transfer the Contribution of such Contributor, if any, in source code and
object code form. This patent license shall apply to the combination of the
Contribution and the Program if, at the time the Contribution is added by the
Contributor, such addition of the Contribution causes such combination to be
covered by the Licensed Patents. The patent license shall not apply to any
other combinations which include the Contribution. No hardware per se is
licensed hereunder.
c) Recipient understands that although each Contributor grants the
licenses to its Contributions set forth herein, no assurances are provided by
any Contributor that the Program does not infringe the patent or other
intellectual property rights of any other entity. Each Contributor disclaims
any liability to Recipient for claims brought by any other entity based on
infringement of intellectual property rights or otherwise. As a condition to
exercising the rights and licenses granted hereunder, each Recipient hereby
assumes sole responsibility to secure any other intellectual property rights
needed, if any. For example, if a third party patent license is required to
allow Recipient to distribute the Program, it is Recipient's responsibility to
acquire that license before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient
copyright rights in its Contribution, if any, to grant the copyright license
set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under
its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties and
conditions, express and implied, including warranties or conditions of title
and non-infringement, and implied warranties or conditions of merchantability
and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for
damages, including direct, indirect, special, incidental and consequential
damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are
offered by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such
Contributor, and informs licensees how to obtain it in a reasonable manner on
or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the
Program.
Contributors may not remove or alter any copyright notices contained within the
Program.
Each Contributor must identify itself as the originator of its Contribution, if
any, in a manner that reasonably allows subsequent Recipients to identify the
originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities with
respect to end users, business partners and the like. While this license is
intended to facilitate the commercial use of the Program, the Contributor who
includes the Program in a commercial product offering should do so in a manner
which does not create potential liability for other Contributors. Therefore, if
a Contributor includes the Program in a commercial product offering, such
Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
every other Contributor ("Indemnified Contributor") against any losses, damages
and costs (collectively "Losses") arising from claims, lawsuits and other legal
actions brought by a third party against the Indemnified Contributor to the
extent caused by the acts or omissions of such Commercial Contributor in
connection with its distribution of the Program in a commercial product
offering. The obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In order
to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
Contributor in writing of such claim, and b) allow the Commercial Contributor
to control, and cooperate with the Commercial Contributor in, the defense and
any related settlement negotiations. The Indemnified Contributor may
participate in any such claim at its own expense.
For example, a Contributor might include the Program in a commercial product
offering, Product X. That Contributor is then a Commercial Contributor. If that
Commercial Contributor then makes performance claims, or offers warranties
related to Product X, those performance claims and warranties are such
Commercial Contributor's responsibility alone. Under this section, the
Commercial Contributor would have to defend claims against the other
Contributors related to those performance claims and warranties, and if a court
requires any other Contributor to pay any damages as a result, the Commercial
Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
Recipient is solely responsible for determining the appropriateness of using
and distributing the Program and assumes all risks associated with its exercise
of rights under this Agreement, including but not limited to the risks and
costs of program errors, compliance with applicable laws, damage to or loss of
data, programs or equipment, and unavailability or interruption of operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under applicable
law, it shall not affect the validity or enforceability of the remainder of the
terms of this Agreement, and without further action by the parties hereto, such
provision shall be reformed to the minimum extent necessary to make such
provision valid and enforceable.
If Recipient institutes patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging that the
Program itself (excluding combinations of the Program with other software or
hardware) infringes such Recipient's patent(s), then such Recipient's rights
granted under Section 2(b) shall terminate as of the date such litigation is
filed.
All Recipient's rights under this Agreement shall terminate if it fails to
comply with any of the material terms or conditions of this Agreement and does
not cure such failure in a reasonable period of time after becoming aware of
such noncompliance. If all Recipient's rights under this Agreement terminate,
Recipient agrees to cease use and distribution of the Program as soon as
reasonably practicable. However, Recipient's obligations under this Agreement
and any licenses granted by Recipient relating to the Program shall continue
and survive.
Everyone is permitted to copy and distribute copies of this Agreement, but in
order to avoid inconsistency the Agreement is copyrighted and may only be
modified in the following manner. The Agreement Steward reserves the right to
publish new versions (including revisions) of this Agreement from time to time.
No one other than the Agreement Steward has the right to modify this Agreement.
The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to
serve as the Agreement Steward to a suitable separate entity. Each new version
of the Agreement will be given a distinguishing version number. The Program
(including Contributions) may always be distributed subject to the version of
the Agreement under which it was received. In addition, after a new version of
the Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly stated
in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
the intellectual property of any Contributor under this Agreement, whether
expressly, by implication, estoppel or otherwise. All rights in the Program not
expressly granted under this Agreement are reserved.
This Agreement is governed by the laws of the State of New York and the
intellectual property laws of the United States of America. No party to this
Agreement will bring a legal action under this Agreement more than one year
after the cause of action arose. Each party waives its rights to a jury trial
in any resulting litigation.

View File

@@ -0,0 +1,472 @@
package org.junit;
import org.junit.function.ThrowingRunnable;
//BSD License
//
//Copyright (c) 2000-2006, www.hamcrest.org
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions are met:
//
//Redistributions of source code must retain the above copyright notice, this list of
//conditions and the following disclaimer. Redistributions in binary form must reproduce
//the above copyright notice, this list of conditions and the following disclaimer in
//the documentation and/or other materials provided with the distribution.
//
//Neither the name of Hamcrest nor the names of its contributors may be used to endorse
//or promote products derived from this software without specific prior written
//permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
//BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
//WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//DAMAGE.
/*
* MODIFIED version of JUnit 4.13 as available at
* https://search.maven.org/remotecontent?filepath=junit/junit/4.13/junit-4.13-sources.jar
* Only parts of this file have been retained for test purposes.
*/
public class Assert {
/**
* Asserts that a condition is true. If it isn't it throws an
* {@link AssertionError} with the given message.
*
* @param message the identifying message for the {@link AssertionError}
* (<code>null</code>
* okay)
* @param condition condition to be checked
*/
static public void assertTrue(String message, boolean condition) {
return;
}
/**
* Asserts that a condition is true. If it isn't it throws an
* {@link AssertionError} without a message.
*
* @param condition condition to be checked
*/
static public void assertTrue(boolean condition) {
return;
}
/**
* Asserts that a condition is false. If it isn't it throws an
* {@link AssertionError} with the given message.
*
* @param message the identifying message for the {@link AssertionError}
* (<code>null</code>
* okay)
* @param condition condition to be checked
*/
static public void assertFalse(String message, boolean condition) {
return;
}
/**
* Asserts that a condition is false. If it isn't it throws an
* {@link AssertionError} without a message.
*
* @param condition condition to be checked
*/
static public void assertFalse(boolean condition) {
return;
}
/**
* Fails a test with the given message.
*
* @param message the identifying message for the {@link AssertionError}
* (<code>null</code>
* okay)
* @see AssertionError
*/
static public void fail(String message) {
if (message == null) {
throw new AssertionError();
}
throw new AssertionError(message);
}
/**
* Asserts that an object isn't null. If it is an {@link AssertionError} is
* thrown with the given message.
*
* @param message the identifying message for the {@link AssertionError}
* (<code>null</code>
* okay)
* @param object Object to check or <code>null</code>
*/
static public void assertNotNull(String message, Object object) {
return;
}
/**
* Asserts that an object isn't null. If it is an {@link AssertionError} is
* thrown.
*
* @param object Object to check or <code>null</code>
*/
static public void assertNotNull(Object object) {
return;
}
/**
* Asserts that an object is null. If it is not, an {@link AssertionError}
* is thrown with the given message.
*
* @param message the identifying message for the {@link AssertionError}
* (<code>null</code>
* okay)
* @param object Object to check or <code>null</code>
*/
static public void assertNull(String message, Object object) {
return;
}
/**
* Asserts that an object is null. If it isn't an {@link AssertionError} is
* thrown.
*
* @param object Object to check or <code>null</code>
*/
static public void assertNull(Object object) {
return;
}
private static boolean equalsRegardingNull(Object expected, Object actual) {
if (expected == null) {
return actual == null;
}
return isEquals(expected, actual);
}
private static boolean isEquals(Object expected, Object actual) {
return expected.equals(actual);
}
/**
* Asserts that two doubles are equal to within a positive delta.
* If they are not, an {@link AssertionError} is thrown with the given
* message. If the expected value is infinity then the delta value is
* ignored. NaNs are considered equal:
* <code>assertEquals(Double.NaN, Double.NaN, *)</code> passes
*
* @param message the identifying message for the {@link AssertionError}
* (<code>null</code>
* okay)
* @param expected expected value
* @param actual the value to check against <code>expected</code>
* @param delta the maximum delta between <code>expected</code> and
* <code>actual</code> for which both numbers are still
* considered equal.
*/
public static void assertEquals(String message, double expected,
double actual, double delta) {
return;
}
private static void failNotEquals(String message, Object expected,
Object actual) {
fail(format(message, expected, actual));
}
static String format(String message, Object expected, Object actual) {
String formatted = "";
if (message != null && !"".equals(message)) {
formatted = message + " ";
}
String expectedString = String.valueOf(expected);
String actualString = String.valueOf(actual);
if (equalsRegardingNull(expectedString, actualString)) {
return formatted + "expected: "
+ formatClassAndValue(expected, expectedString)
+ " but was: " + formatClassAndValue(actual, actualString);
} else {
return formatted + "expected:<" + expectedString + "> but was:<"
+ actualString + ">";
}
}
private static String formatClass(Class<?> value) {
String className = value.getCanonicalName();
return className == null ? value.getName() : className;
}
private static String formatClassAndValue(Object value, String valueString) {
String className = value == null ? "null" : value.getClass().getName();
return className + "<" + valueString + ">";
}
/**
* Asserts that two floats are equal to within a positive delta.
* If they are not, an {@link AssertionError} is thrown with the given
* message. If the expected value is infinity then the delta value is
* ignored. NaNs are considered equal:
* <code>assertEquals(Float.NaN, Float.NaN, *)</code> passes
*
* @param message the identifying message for the {@link AssertionError}
* (<code>null</code>
* okay)
* @param expected expected value
* @param actual the value to check against <code>expected</code>
* @param delta the maximum delta between <code>expected</code> and
* <code>actual</code> for which both numbers are still
* considered equal.
*/
public static void assertEquals(String message, float expected, float actual,
float delta) {
if (floatIsDifferent(expected, actual, delta)) {
failNotEquals(message, Float.valueOf(expected), Float.valueOf(actual));
}
}
private static boolean doubleIsDifferent(double d1, double d2, double delta) {
if (Double.compare(d1, d2) == 0) {
return false;
}
if ((Math.abs(d1 - d2) <= delta)) {
return false;
}
return true;
}
private static boolean floatIsDifferent(float f1, float f2, float delta) {
if (Float.compare(f1, f2) == 0) {
return false;
}
if ((Math.abs(f1 - f2) <= delta)) {
return false;
}
return true;
}
/**
* Asserts that two longs are equal. If they are not, an
* {@link AssertionError} is thrown.
*
* @param expected expected long value.
* @param actual actual long value
*/
public static void assertEquals(long expected, long actual) {
assertEquals(null, expected, actual);
}
/**
* Asserts that two longs are equal. If they are not, an
* {@link AssertionError} is thrown with the given message.
*
* @param message the identifying message for the {@link AssertionError}
* (<code>null</code>
* okay)
* @param expected long expected value.
* @param actual long actual value
*/
public static void assertEquals(String message, long expected, long actual) {
if (expected != actual) {
failNotEquals(message, Long.valueOf(expected), Long.valueOf(actual));
}
}
/**
* @deprecated Use
* <code>assertEquals(double expected, double actual, double
* delta)</code> instead
*/
@Deprecated
public static void assertEquals(double expected, double actual) {
assertEquals(null, expected, actual);
}
/**
* @deprecated Use
* <code>assertEquals(String message, double expected, double
* actual, double delta)</code> instead
*/
@Deprecated
public static void assertEquals(String message, double expected,
double actual) {
fail("Use assertEquals(expected, actual, delta) to compare " +
"floating-point numbers");
}
/**
* Asserts that two doubles are equal to within a positive delta.
* If they are not, an {@link AssertionError} is thrown. If the expected
* value is infinity then the delta value is ignored.NaNs are considered
* equal: <code>assertEquals(Double.NaN, Double.NaN, *)</code> passes
*
* @param expected expected value
* @param actual the value to check against <code>expected</code>
* @param delta the maximum delta between <code>expected</code> and
* <code>actual</code> for which both numbers are still
* considered equal.
*/
public static void assertEquals(double expected, double actual,
double delta) {
assertEquals(null, expected, actual, delta);
}
/**
* Asserts that two floats are equal to within a positive delta.
* If they are not, an {@link AssertionError} is thrown. If the expected
* value is infinity then the delta value is ignored. NaNs are considered
* equal: <code>assertEquals(Float.NaN, Float.NaN, *)</code> passes
*
* @param expected expected value
* @param actual the value to check against <code>expected</code>
* @param delta the maximum delta between <code>expected</code> and
* <code>actual</code> for which both numbers are still
* considered equal.
*/
public static void assertEquals(float expected, float actual, float delta) {
assertEquals(null, expected, actual, delta);
}
/**
* Asserts that two objects are equal. If they are not, an
* {@link AssertionError} without a message is thrown. If
* <code>expected</code> and <code>actual</code> are <code>null</code>,
* they are considered equal.
*
* @param expected expected value
* @param actual the value to check against <code>expected</code>
*/
public static void assertEquals(Object expected, Object actual) {
assertEquals(null, expected, actual);
}
public static void assertEquals(String message, Object expected,
Object actual) {
}
public static void assertNotEquals(String message, Object unexpected, Object actual) {
return;
}
public static void assertNotEquals(Object unexpected, Object actual) {
assertNotEquals(null, unexpected, actual);
}
public static void assertNotEquals(String message, long unexpected, long actual) {
return;
}
public static void assertNotEquals(long unexpected, long actual) {
assertNotEquals(null, unexpected, actual);
}
public static void assertNotEquals(String message, double unexpected, double actual, double delta) {
return;
}
public static void assertNotEquals(double unexpected, double actual, double delta) {
assertNotEquals(null, unexpected, actual, delta);
}
public static void assertNotEquals(String message, float unexpected, float actual, float delta) {
return;
}
public static void assertNotEquals(float unexpected, float actual, float delta) {
assertNotEquals(null, unexpected, actual, delta);
}
public static void assertNotSame(String message, Object unexpected, Object actual) {
return;
}
public static void assertNotSame(Object unexpected, Object actual) {
assertNotSame(null, unexpected, actual);
}
public static void assertSame(String message, Object expected, Object actual) {
return;
}
public static void assertSame(Object expected, Object actual) {
assertSame(null, expected, actual);
}
/**
* Asserts that {@code runnable} throws an exception of type {@code expectedThrowable} when
* executed. If it does, the exception object is returned. If it does not throw an exception, an
* {@link AssertionError} is thrown. If it throws the wrong type of exception, an {@code
* AssertionError} is thrown describing the mismatch; the exception that was actually thrown can
* be obtained by calling {@link AssertionError#getCause}.
*
* @param expectedThrowable the expected type of the exception
* @param runnable a function that is expected to throw an exception when executed
* @return the exception thrown by {@code runnable}
* @since 4.13
*/
public static <T extends Throwable> T assertThrows(Class<T> expectedThrowable,
ThrowingRunnable runnable) {
return assertThrows(null, expectedThrowable, runnable);
}
/**
* Asserts that {@code runnable} throws an exception of type {@code expectedThrowable} when
* executed. If it does, the exception object is returned. If it does not throw an exception, an
* {@link AssertionError} is thrown. If it throws the wrong type of exception, an {@code
* AssertionError} is thrown describing the mismatch; the exception that was actually thrown can
* be obtained by calling {@link AssertionError#getCause}.
*
* @param message the identifying message for the {@link AssertionError} (<code>null</code>
* okay)
* @param expectedThrowable the expected type of the exception
* @param runnable a function that is expected to throw an exception when executed
* @return the exception thrown by {@code runnable}
* @since 4.13
*/
public static <T extends Throwable> T assertThrows(String message, Class<T> expectedThrowable,
ThrowingRunnable runnable) {
try {
runnable.run();
} catch (Throwable actualThrown) {
if (expectedThrowable.isInstance(actualThrown)) {
@SuppressWarnings("unchecked") T retVal = (T) actualThrown;
return retVal;
} else {
String expected = formatClass(expectedThrowable);
Class<? extends Throwable> actualThrowable = actualThrown.getClass();
String actual = formatClass(actualThrowable);
if (expected.equals(actual)) {
// There must be multiple class loaders. Add the identity hash code so the message
// doesn't say "expected: java.lang.String<my.package.MyException> ..."
expected += "@" + Integer.toHexString(System.identityHashCode(expectedThrowable));
actual += "@" + Integer.toHexString(System.identityHashCode(actualThrowable));
}
String mismatchMessage = buildPrefix(message)
+ format("unexpected exception type thrown;", expected, actual);
// The AssertionError(String, Throwable) ctor is only available on JDK7.
AssertionError assertionError = new AssertionError(mismatchMessage);
assertionError.initCause(actualThrown);
throw assertionError;
}
}
String notThrownMessage = buildPrefix(message) + String
.format("expected %s to be thrown, but nothing was thrown",
formatClass(expectedThrowable));
throw new AssertionError(notThrownMessage);
}
private static String buildPrefix(String message) {
return message != null && message.length() != 0 ? message + ": " : "";
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2015-2018 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v2.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v20.html
*/
/*
* MODIFIED version of junit-jupiter-api 5.2.0 as available at
* https://search.maven.org/classic/remotecontent?filepath=org/junit/jupiter/junit-jupiter-api/5.2.0/junit-jupiter-api-5.2.0-sources.jar
* Only parts of this file have been retained for test purposes.
*/
package org.junit;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Test {}

View File

@@ -0,0 +1,14 @@
package org.junit.function;
/**
* This interface facilitates the use of
* {@link org.junit.Assert#assertThrows(Class, ThrowingRunnable)} from Java 8. It allows method
* references to void methods (that declare checked exceptions) to be passed directly into
* {@code assertThrows}
* without wrapping. It is not meant to be implemented directly.
*
* @since 4.13
*/
public interface ThrowingRunnable {
void run() throws Throwable;
}

View File

@@ -0,0 +1,4 @@
package org.mockito;
public class ArgumentMatchers {
}

View File

@@ -0,0 +1,10 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito;
import java.io.Serializable;
public interface MockSettings extends Serializable {
}

View File

@@ -0,0 +1,216 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito;
import org.mockito.ArgumentMatchers;
import org.mockito.MockSettings;
import org.mockito.internal.creation.MockSettingsImpl;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.OngoingStubbing;
import org.mockito.internal.MockitoCore;
import org.mockito.MockSettings;
import org.mockito.stubbing.Stubber;
public class Mockito extends ArgumentMatchers {
static final MockitoCore MOCKITO_CORE = new MockitoCore();
public static MockSettings withSettings() {
return new MockSettings() {
};
}
/**
* Creates a mock object of the requested class or interface.
* <p>
* See examples in javadoc for the {@link Mockito} class.
*
* @param reified don't pass any values to it. It's a trick to detect the
* class/interface you
* want to mock.
* @return the mock object.
* @since 4.10.0
*/
@SafeVarargs
public static <T> T mock(T... reified) {
return mock(withSettings(), reified);
}
/**
* Creates a mock object of the requested class or interface with the given
* default answer.
* <p>
* See examples in javadoc for the {@link Mockito} class.
*
* @param defaultAnswer the default answer to use.
* @param reified don't pass any values to it. It's a trick to detect the
* class/interface you
* want to mock.
* @return the mock object.
* @since 5.1.0
*/
@SafeVarargs
public static <T> T mock(@SuppressWarnings("rawtypes") Answer defaultAnswer, T... reified) {
return mock(new Answer<T>() {
}, reified);
}
/**
* Creates a mock object of the requested class or interface with the given
* name.
* <p>
* See examples in javadoc for the {@link Mockito} class.
*
* @param name the mock name to use.
* @param reified don't pass any values to it. It's a trick to detect the
* class/interface you
* want to mock.
* @return the mock object.
* @since 5.1.0
*/
@SafeVarargs
public static <T> T mock(String name, T... reified) {
return mock(withSettings(), reified);
}
/**
* Creates a mock object of the requested class or interface with the given
* settings.
* <p>
* See examples in javadoc for the {@link Mockito} class.
*
* @param settings the mock settings to use.
* @param reified don't pass any values to it. It's a trick to detect the
* class/interface you
* want to mock.
* @return the mock object.
* @since 5.1.0
*/
@SafeVarargs
public static <T> T mock(MockSettings settings, T... reified) {
if (reified == null || reified.length > 0) {
throw new IllegalArgumentException(
"Please don't pass any values here. Java will detect class automagically.");
}
return mock(getClassOf(reified), settings);
}
/**
* Creates mock object of given class or interface.
* <p>
* See examples in javadoc for {@link Mockito} class
*
* @param classToMock class or interface to mock
* @return mock object
*/
public static <T> T mock(Class<T> classToMock) {
return mock(classToMock, withSettings());
}
/**
* Specifies mock name. Naming mocks can be helpful for debugging - the name is
* used in all verification errors.
* <p>
* Beware that naming mocks is not a solution for complex code which uses too
* many mocks or collaborators.
* <b>If you have too many mocks then refactor the code</b> so that it's easy to
* test/debug without necessity of naming mocks.
* <p>
* <b>If you use <code>&#064;Mock</code> annotation then you've got naming mocks
* for free!</b> <code>&#064;Mock</code> uses field name as mock name.
* {@link Mock Read more.}
* <p>
*
* See examples in javadoc for {@link Mockito} class
*
* @param classToMock class or interface to mock
* @param name of the mock
* @return mock object
*/
public static <T> T mock(Class<T> classToMock, String name) {
return mock(classToMock, new Answer<T>() {
});
}
/**
* Creates mock with a specified strategy for its answers to interactions.
* It's quite an advanced feature and typically you don't need it to write
* decent tests.
* However it can be helpful when working with legacy systems.
* <p>
* It is the default answer so it will be used <b>only when you don't</b> stub
* the method call.
*
* <pre class="code">
* <code class="java">
* Foo mock = mock(Foo.class, RETURNS_SMART_NULLS);
* Foo mockTwo = mock(Foo.class, new YourOwnAnswer());
* </code>
* </pre>
*
* <p>
* See examples in javadoc for {@link Mockito} class
* </p>
*
* @param classToMock class or interface to mock
* @param defaultAnswer default answer for un-stubbed methods
*
* @return mock object
*/
public static <T> T mock(Class<T> classToMock, Answer defaultAnswer) {
return mock(classToMock, new Answer<T>() {
});
}
/**
* Creates a mock with some non-standard settings.
* <p>
* The number of configuration points for a mock will grow,
* so we need a fluent way to introduce new configuration without adding more
* and more overloaded Mockito.mock() methods.
* Hence {@link MockSettings}.
*
* <pre class="code">
* <code class="java">
* Listener mock = mock(Listener.class, withSettings()
* .name("firstListner").defaultBehavior(RETURNS_SMART_NULLS));
* );
* </code>
* </pre>
*
* <b>Use it carefully and occasionally</b>. What might be reason your test
* needs non-standard mocks?
* Is the code under test so complicated that it requires non-standard mocks?
* Wouldn't you prefer to refactor the code under test, so that it is testable
* in a simple way?
* <p>
* See also {@link Mockito#withSettings()}
* <p>
* See examples in javadoc for {@link Mockito} class
*
* @param classToMock class or interface to mock
* @param mockSettings additional mock settings
* @return mock object
*/
public static <T> T mock(Class<T> classToMock, MockSettings mockSettings) {
return MOCKITO_CORE.mock(classToMock, mockSettings);
}
private static <T> Class<T> getClassOf(T[] array) {
return (Class<T>) array.getClass().getComponentType();
}
public static <T> OngoingStubbing<T> when(T methodCall) {
return MOCKITO_CORE.when(methodCall);
}
public static Stubber doReturn(Object toBeReturned) {
return null;
}
public static Stubber doReturn(Object toBeReturned, Object... toBeReturnedNext) {
return null;
}
}

View File

@@ -0,0 +1,28 @@
package org.mockito.internal;
import org.mockito.MockSettings;
import org.mockito.internal.creation.MockSettingsImpl;
import org.mockito.internal.progress.MockingProgress;
import org.mockito.stubbing.OngoingStubbing;
import org.mockito.mock.MockCreationSettings;
import static org.mockito.internal.util.MockUtil.createMock;
public class MockitoCore {
public <T> T mock(Class<T> typeToMock, MockSettings settings) {
MockSettingsImpl impl = (MockSettingsImpl) settings;
MockCreationSettings<T> creationSettings = impl.build(typeToMock);
T mock = createMock(creationSettings);
return mock;
}
public <T> OngoingStubbing<T> when(T methodCall) {
MockingProgress mockingProgress = new MockingProgress() {
@Override
public OngoingStubbing<?> pullOngoingStubbing() {
return null;
}
};
OngoingStubbing<T> stubbing = (OngoingStubbing<T>) mockingProgress.pullOngoingStubbing();
return stubbing;
}
}

View File

@@ -0,0 +1,14 @@
package org.mockito.internal.creation;
import org.mockito.MockSettings;
import org.mockito.mock.MockCreationSettings;
public class MockSettingsImpl<T> implements MockSettings {
public <T2> MockCreationSettings<T2> build(Class<T2> typeToMock) {
return new MockCreationSettings<T2>() {
public String getMockMaker() {
return null;
}
};
}
}

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.handler;
import org.mockito.mock.MockCreationSettings;
import org.mockito.invocation.MockHandler;
public final class MockHandlerFactory {
public static <T> MockHandler<T> createMockHandler(MockCreationSettings<T> settings) {
return new MockHandlerImpl<T>();
}
}

View File

@@ -0,0 +1,10 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.handler;
import org.mockito.invocation.MockHandler;
public class MockHandlerImpl<T> implements MockHandler<T> {
}

View File

@@ -0,0 +1,11 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.progress;
import org.mockito.stubbing.OngoingStubbing;
public interface MockingProgress {
OngoingStubbing<?> pullOngoingStubbing();
}

View File

@@ -0,0 +1,18 @@
package org.mockito.internal.util;
import org.mockito.mock.MockCreationSettings;
import org.mockito.plugins.MockMaker;
import org.mockito.invocation.MockHandler;
import static org.mockito.internal.handler.MockHandlerFactory.createMockHandler;
public class MockUtil {
public static <T> T createMock(MockCreationSettings<T> settings) {
MockMaker mockMaker = getMockMaker(settings.getMockMaker());
MockHandler mockHandler = createMockHandler(settings);
return mockMaker.createMock(settings, mockHandler);
}
public static MockMaker getMockMaker(String mockMaker) {
return null;
}
}

View File

@@ -0,0 +1,10 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.invocation;
import java.io.Serializable;
public interface MockHandler<T> extends Serializable {
}

View File

@@ -0,0 +1,9 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.mock;
public interface MockCreationSettings<T> {
String getMockMaker();
}

View File

@@ -0,0 +1,8 @@
package org.mockito.plugins;
import org.mockito.mock.MockCreationSettings;
import org.mockito.invocation.MockHandler;
public interface MockMaker {
<T> T createMock(MockCreationSettings<T> settings, MockHandler handler);
}

View File

@@ -0,0 +1,7 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.stubbing;
public interface Answer<T> { }

View File

@@ -0,0 +1,9 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.stubbing;
public interface OngoingStubbing<T> {
OngoingStubbing<T> thenReturn(T value);
}

View File

@@ -0,0 +1,5 @@
package org.mockito.stubbing;
public interface Stubber {
<T> T when(T mock);
}