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

Add JMockit's MockUp to Mockito migration #599

Merged
merged 61 commits into from
Nov 2, 2024
Merged

Conversation

SiBorea
Copy link
Contributor

@SiBorea SiBorea commented Sep 11, 2024

What's changed?

Add JMockit MockUp to Mockito

What's your motivation?

Checklist

  • [✅] I've added unit tests to cover both positive and negative cases
  • [✅] I've read and applied the recipe conventions and best practices
  • [✅] I've used the IntelliJ IDEA auto-formatter on affected files

Copy link
Contributor

@timtebeek timtebeek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great addition @SiBorea ! I've pushed up a small change and left two initial comments; I'd need a little more time for a full review, but this is looking very promising.

Tagging @tinder-dthomson and @shivanisky for additional review (if possible), since they have more experience with JMockit migrations.

@shivanisky
Copy link
Collaborator

Awesome for working on this!

@tinder-dthomson
Copy link
Contributor

@timtebeek @SiBorea hey folks! I am a bit unavailable at the moment as I'm currently caring for a one-week old newborn 😄

I'll try to take a look when I get some free time, but please don't depend on me for ongoing efforts for the time being!

@shivanisky
Copy link
Collaborator

shivanisky commented Sep 12, 2024

Congrats on new baby!

@shivanisky
Copy link
Collaborator

shivanisky commented Sep 12, 2024

Looking at the unit tests, we can't migrate Mockup directly to mock + when statements. Because Mockup is typically used to stub a subset of methods while the remaining methods behave as specified in the original class.

https://javadoc.io/doc/org.jmockit/jmockit/latest/mockit/MockUp.html

If we directly migrate to mock+when, then this will cause failures in all cases where a subset of methods are stubbed in the mockup. And this would be the most common outcome.

I think best to use spy for non static.

For static, private or final, may try PowerMockito - haven't tried this.

But even this doesn't work in all cases and isn't a direct migration, but may cover most of the cases. I haven't seen enough MockUps to know.

For direct migration Byte code injection/cglib may be needed. That would probably cover all the cases but it's a tough one.

Maybe even worth going through jmockit source code and replicating what they are doing - probably byte code injection.

I hope that the above makes sense.

@shivanisky
Copy link
Collaborator

shivanisky commented Sep 12, 2024

You could do it in the following way if you don't want to use byte code injection:

  1. If in the MockUp, only static methods, then use MockStatic as you have already
  2. If non static methods, use spy only and the standard Mockito when
  3. If a mix, use both above - not sure if it will work, but one can hope.

Will need to use doAnswer for multiline method bodies and anything that uses the method args ... as thenAnswer doesn't support void methods. Can use thenAnswer for non void, and doAnswer for void, or to simplify I think doAnswer supports both, may be better to just stick with that. Will need to handle the case for method params. This is very similar to migrating JMockit Delegate.

To understand for the full migration, why byte code injection is needed JMockit allows this:

new MockUp<Bla> {
    void bla() {
    // custom
   }
}


// so where deep in the dev code this instance is created 
Bla bla = new Bla();
bla.bla(); // this will run custom above 

And can't be done without bytecode injection. Not sure if PowerMockito support this.

@SiBorea
Copy link
Contributor Author

SiBorea commented Sep 12, 2024

There will be a possibility that multiple new object statements after MockUp. Using spy may have to insert code every occurrence. And I suppose most likely those stubbed methods will not be called (at lease in my project). MockConstruction is better under this circumstance.
Nice suggestion to use doAnswer for both void and non void methods, will try.

Powermock has been inactive for years, and has compatibility issues about JDK17 and high version of Mockito. Don't feel like a good solution.
Furthermore, Mockito's claim about mocking private/final method sound to me.
https://github.com/mockito/mockito/wiki/Mockito-And-Private-Methods
Do you think we should support these? It's a JMockit to Mockito 5 recipe.

@SiBorea
Copy link
Contributor Author

SiBorea commented Sep 12, 2024

Do we have byte code injection example in OpenRewrite? Haven't seen it before

@shivanisky
Copy link
Collaborator

shivanisky commented Sep 12, 2024 via email

@SiBorea
Copy link
Contributor Author

SiBorea commented Sep 13, 2024

I think PowerMockito is the same as PowerMock, quote Basically, PowerMock provides a class called "PowerMockito" for creating mock/object/class and initiating verification, and expectations, everything else you can still use Mockito to setup and verify expectation (e.g. times(), anyInt()).

I guess people copied and pasted the MockUp code from somewhere in my case. I saw MockUp everywhere and no Expectation.

SiBorea and others added 3 commits September 13, 2024 15:54
…UpToMockitoTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…UpToMockitoTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…UpToMockitoTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
SiBorea and others added 3 commits October 24, 2024 10:23
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some suggestions could not be made:

  • src/main/java/org/openrewrite/java/testing/jmockit/JMockitBlockRewriter.java
    • lines 112-113

@timtebeek timtebeek added enhancement New feature or request recipe Recipe request labels Oct 27, 2024
@timtebeek
Copy link
Contributor

@SiBorea Thanks a lot for the coverage of MockUp here; I've fixed to compilation here but noticed the tests are still failing with a classcast exception; did you see the same there?

Caused by: java.lang.ClassCastException: class org.openrewrite.java.tree.J$MethodDeclaration cannot be cast to class org.openrewrite.java.tree.J$Block (org.openrewrite.java.tree.J$MethodDeclaration and org.openrewrite.java.tree.J$Block are in unnamed module of loader 'app')
	at org.openrewrite.java.testing.jmockit.SetupStatementsRewriter.rewriteMethodBody(SetupStatementsRewriter.java:53)
	at org.openrewrite.java.testing.jmockit.JMockitBlockToMockito$RewriteJMockitBlockVisitor.visitMethodDeclaration(JMockitBlockToMockito.java:69)
	at org.openrewrite.java.testing.jmockit.JMockitBlockToMockito$RewriteJMockitBlockVisitor.visitMethodDeclaration(JMockitBlockToMockito.java:59)
	at org.openrewrite.java.tree.J$MethodDeclaration.acceptJava(J.java:3651)
	at org.openrewrite.java.tree.J.accept(J.java:59)
	at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
	... 49 more

timtebeek added a commit that referenced this pull request Oct 29, 2024
@SiBorea
Copy link
Contributor Author

SiBorea commented Nov 1, 2024

@timtebeek Hi, I misunderstood the root cause of the failing tests. It should be fixed now. Please run the workflow again.

timtebeek added a commit to openrewrite/rewrite-static-analysis that referenced this pull request Nov 2, 2024
Copy link
Contributor

@timtebeek timtebeek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the work here @SiBorea ; I know it's been a long way to work through all the feedback. Massive thanks as well to @shivanisky for the help in guiding and reviewing this PR.

I've applied a few final touches, also with a change in rewrite-static-analysis, and with that I think we're good to merge this iteration. Thanks a lot!

@timtebeek timtebeek merged commit 72232f7 into openrewrite:main Nov 2, 2024
2 checks passed
@timtebeek timtebeek mentioned this pull request Nov 2, 2024
@shivanisky
Copy link
Collaborator

shivanisky commented Nov 2, 2024

Thanks a lot for the work here @SiBorea ; I know it's been a long way to work through all the feedback. Massive thanks as well to @shivanisky for the help in guiding and reviewing this PR.

I've applied a few final touches, also with a change in rewrite-static-analysis, and with that I think we're good to merge this iteration. Thanks a lot!

Great to see this in - thanks a lot @timtebeek and @SiBorea - a great effort. Now almost all the JMockit types are migrated - Expectations (except for Delegate - this PR will help a lot with that as the migration of Mockup method is almost the same as Delegate), NonStrictExpectations, Verifications, FullVerifications, MockUp.

Only 2 JMockit types left: Expectations Delegate and VerificationsInOrder

@SiBorea SiBorea deleted the mockup branch November 4, 2024 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request recipe Recipe request
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants