Repository: mockito/mockito
Issue: `toString()` seems to be broken on 3.6.28
Labels: please contribute

Hi guys, I think the `toString()` method was broken recently, I have a test for mockito-scala that checks a mock `toString` invocation returns its name, but if I try to update to said version it returns the standard `Object` implementation of `toString`.

I tried with the "pure" Java API of Mockito and the same thing happens

Thanks!




Issue comments:
The release diff (https://github.com/mockito/mockito/compare/v3.6.0...v3.6.28) points to #2098 most likely. Can you do a bisect to figure out if that is indeed the problematic PR?
Possibly related and maybe helpful in diagnosing is that attempting to work around this issue by adding an explicit stub for `toString` (e.g. `when(someMock.toString()).thenReturn("someMock")`) will cause a `MissingMethodInvocationException`:

```text
org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
```
Could you try downgrading ByteBuddy to 1.10.15 and see if that resolves the issue?
I can confirm. I am facing the same issue when upgrading from 3.2.0 to 3.7.7.
Hi there,

I came across this bug and decided to have a look. I cannot reproduce it. Maybe I've got something wrong here. Anyway, I provided a test repository with a test build which we may use to get behind things here.

https://github.com/JanMosigItemis/mockito_issue_2154

Let me know how things go 👋
Hi @JanMosigItemis 

I was able to reproduce the issue with your test repository. Just replace "mockito-core" with "mockito-inline"

```
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-core</artifactId>
                <version>${mockito.version}</version>
                <scope>test</scope>
            </dependency>
```

```
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-inline</artifactId>
                <version>${mockito.version}</version>
                <scope>test</scope>
            </dependency>
```

You should get:
```
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running de.itemis.jmo.mockito.issue2154.MockitoIssue2154JUnit5Test
[ERROR] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.526 s <<< FAILURE! - in de.itemis.jmo.mockito.issue2154.MockitoIssue2154JUnit5Test
[ERROR] test_stubbed_to_string_works  Time elapsed: 0.054 s  <<< ERROR!
org.mockito.exceptions.misusing.MissingMethodInvocationException: 

when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

	at de.itemis.jmo.mockito.issue2154.MockitoIssue2154JUnit5Test.test_stubbed_to_string_works(MockitoIssue2154JUnit5Test.java:26)

[INFO] Running de.itemis.jmo.mockito.issue2154.MockitoIssue2154JUnit4Test
[ERROR] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.041 s <<< FAILURE! - in de.itemis.jmo.mockito.issue2154.MockitoIssue2154JUnit4Test
[ERROR] test_stubbed_to_string_works  Time elapsed: 0.018 s  <<< ERROR!
org.mockito.exceptions.misusing.MissingMethodInvocationException: 

when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

	at de.itemis.jmo.mockito.issue2154.MockitoIssue2154JUnit4Test.test_stubbed_to_string_works(MockitoIssue2154JUnit4Test.java:26)

[INFO] 
[INFO] Results:
[INFO] 
[ERROR] Errors: 
[ERROR]   MockitoIssue2154JUnit4Test.test_stubbed_to_string_works:26 MissingMethodInvocation
[ERROR]   MockitoIssue2154JUnit5Test.test_stubbed_to_string_works:26 MissingMethodInvocation
[INFO] 
[ERROR] Tests run: 4, Failures: 0, Errors: 2, Skipped: 0
```

Let me know if this info is enough for you or if I should fork your repo.
Thx @pitschr I can reproduce now. The problem is also present in the latest mockito-inline release 3.7.7.
@TimvdLippe I downgraded to byte buddy 1.10.15 via maven exclusion and got the same result.
I had a hunch that in https://github.com/mockito/mockito/pull/2098/files#diff-749d9baac17dc6e18e7db9ee686a840d65ac746dc291b591b37834ba4c8261d1R273 the line `targets.remove(Object.class);` could be the culprit. I removed it on my local machine, build mockito-inline 3.7.9 and used it in my test repo. Works like a charm. Now I've got too few internal mockito knowledge in order to come up with a decent PR on this, bc I don't know exactly why this line has been introduced and if it would be safe to simply remove it. Any thoughts on this?
Thanks for the investigation @JanMosigItemis ! In general, if our full test suite passes with that line removed, it should be safe to do so. Please add a regression test to our test suite as well and then feel free to open a PR for it!
Ok, I'll try.

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
index 5fc47cd7cb..7db8afe97f 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
@@ -269,9 +269,6 @@ private <T> void triggerRetransformation(Set<Class<?>> types, boolean flat) {
             throw t;
         }
 
-        // The object type does not ever need instrumentation.
-        targets.remove(Object.class);
-
         if (!targets.isEmpty()) {
             try {
                 assureCanReadMockito(targets);


Test patch:
diff --git a/src/test/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMakerTest.java b/src/test/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMakerTest.java
index bfc16b4d15..dfa6d8192f 100644
--- a/src/test/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMakerTest.java
+++ b/src/test/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMakerTest.java
@@ -220,6 +220,20 @@ public void should_mock_interface_to_string() {
         assertThat(proxy.toString()).isEqualTo("foo");
     }
 
+    /**
+     * @see <a href="https://github.com/mockito/mockito/issues/2154">https://github.com/mockito/mockito/issues/2154</a>
+     */
+    @Test
+    public void should_mock_class_to_string() {
+        MockSettingsImpl<Object> mockSettings = new MockSettingsImpl<Object>();
+        mockSettings.setTypeToMock(Object.class);
+        mockSettings.defaultAnswer(new Returns("foo"));
+        Object proxy =
+                mockMaker.createMock(mockSettings, new MockHandlerImpl<Object>(mockSettings));
+
+        assertThat(proxy.toString()).isEqualTo("foo");
+    }
+
     @Test
     public void should_remove_recursive_self_call_from_stack_trace() throws Exception {
         StackTraceElement[] stack =