Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect documentation for RETURNS_MOCKS #3285

Open
sergey-morenets opened this issue Mar 1, 2024 · 3 comments
Open

Incorrect documentation for RETURNS_MOCKS #3285

sergey-morenets opened this issue Mar 1, 2024 · 3 comments

Comments

@sergey-morenets
Copy link

Hi

I checked the latest (5.11.0) documentation for Mockito class (https://javadoc.io/static/org.mockito/mockito-core/5.11.0/org/mockito/Mockito.html#23) and it states:
ReturnsMocks first tries to return ordinary values (zeros, empty collections, empty string, etc.) then it tries to return mocks. If the return type cannot be mocked (e.g. is final) then plain null is returned.

I have an enumeration Department with abstract methods (Mockito is unable to mock it). Let's say it's used in OrderRepository:

public interface OrderRepository {
	
	Department getDepartment();
}

Then I inject mocked version of OrderRepository:

@ExtendWith(MockitoExtension.class)
public class OrderServiceTest {

	@Mock(answer = Answers.RETURNS_MOCKS)
	OrderRepository orderRepository;

and when I try to invoke getDepartment():
Department department = orderRepository.getDepartment();

I suppose to receive null value according to the documentation but get an error:
org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class Department.
Sealed abstract enums can't be mocked. Since Java 15 abstract enums are declared sealed, which prevents mocking.
You can still return an existing enum literal from a stubbed method call.
@TimvdLippe
Copy link
Contributor

I am assuming here that Department is an enum here, hence the error message. We delegate this check to MockUtil:

if (!MockUtil.typeMockabilityOf(type, mockSettings.getMockMaker()).mockable()) {

If I understand correctly, we delegate this check to ByteBuddy:

return INSTRUMENTATION.isModifiableClass(type) && !EXCLUDES.contains(type);
Hence I am not sure why ByteBuddy thinks we can mock this type. Can you check whether we indeed hit this check in ByteBuddy and what ByteBuddy returns? That should help us understand why we think we can mock a sealed class, even though we can't.

@sergey-morenets
Copy link
Author

Hi @TimvdLippe

I just checked that code in InlineDelegateByteBuddyMockMaker:

            @Override
            public boolean mockable() {
                return INSTRUMENTATION.isModifiableClass(type) && !EXCLUDES.contains(type);
            }

And INSTRUMENTATION.isModifiableClass(type) returns true for Department.

@sergey-morenets
Copy link
Author

Here's Department:

	enum Department {
		QA {
			@Override
			String getName() {
				return "Quality Assurance";
			}
		},
		DEV {
			@Override
			String getName() {
				return "Development";
			}
		};

		abstract String getName();
	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants