简体   繁体   中英

How to inject final class such as String into constructor of class annotated with @InjectMocks in Mockito 3

I would like to mock the following class:

public class MyRunner {
    private String name;
    private User user;//not final
    public MyRunner(String name, User user) {
      this.name = name;
      this.user = user
    }
    //...something complicated in the methods
}

Just like with JMockit

@ExtendWith(MockitoExtension.class)
public class MyRunnerTest {
    @Inject
    private String name = "sth";
    @Inject
    private User user;
    @Tested
    private MyRunner tested;
}

Similarly with Mockito 3,

@ExtendWith(MockitoExtension.class)
public class MyRunnerTest {
    @Mock
    private String name;
    @Mock
    private User user;
    @InjectMocks
    private MyRunner tested;
    @Test //from JUnit5
    public void testSth() {
      //...
    }
}

Problem : The injection of the name string into the MyRunner during construction would fail due to the fact that String is a final class. Got error message like:

Cannot mock/spy class java.lang.String
Mockito cannot mock/spy because :
 - final class

It is possible to intialize the tested class with new keyword:

@ExtendWith(MockitoExtension.class)
public class MyRunnerTest {
    private String name = "sth";
    @Mock
    private User user;
    private MyRunner tested = new MyRunner(name, user);
    @Test //from JUnit5
    public void testSth() {
      //...
    }
}

However, the solution above is not as fluent as merely using the annotation

Question : How to inject the final class into the object annotated with @InjectMocks instead of constructing it with new keyword explicitly?

There are many approaches to this. Here are 3 conceptually different ones:

Option 1

First off, if you're really talking about the String, than probably mocking it doesn't have much sense: Basically your example doesn't require mockito at all. You can simply:

public class UserTest {
  private final String NAME = "sampleName;

  private User tested = new User(NAME);

 ...
}

Option 2

Now, assuming that you're not really talking about String class here, the best option is to program by Interfaces for which creating Mocks is fairly simple:


public class User {
    public User(Name name) {
      ...
    }

}

public interface Name {
   String getValue();
}

@ExtendsWith(MockitoExtension.class)
public class UserTest

   @Mock
   private Name name;

   @InjectMocks
   private User tested;

Option 3

If you're absolutely required to mock static class, you can do that in mockito but it requires some additional setup: basically you create a file org.mockito.plugins.MockMaker in the directory src/test/resources/mockito-extensions that will contain:

mock-maker-inline

See this tutorial for more information

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM