JMockit : How to inject a MockUp class into a tested class? - java

I'm new to JMockIt and am trying to figure out/understand how to use #Injectable for a top-level MockUp class that I have already defined.
For example:
// JUnit Test Class
public class RepositoryTest {
#Tested private Repository repository;
#Injectable private ResultsAPIWrapper resultsApiWrapper;
#Test
public void testRepo(){
new ResultsApiWrapper();
assertThat(repository.doSomething(), is("done" ) );
}
}
// Class under test
public class Repository{
#Autowired private ResultsAPIWrapper resultsApiWrapper;
public String doSomething(){
return resultsApiWrapper.load();
}
}
// Mocked implementation of the ResultsAPIWrapper that I want injected into Repository
public class ResultsApiWrapperMock extends MockUp<ResultsAPIWrapper>{
#Mock
public String load(){
return "done";
}
}
If I try the above, I get an error
java.lang.IllegalArgumentException: Class already mocked: com.fw.wrappers.ResultsAPIWrapper
at com.fw.wrappers.mock.ResultsApiWrapperMock.<init>(ResultsApiWrapperMock.java:12)
at com.fw.repository.RepositoryTest.testRepo(RepositoryTest.java:38)
But If I remove the new ResultsApiWrapper() then I do not know how to specify which is the class I want to use as my mocked implementation for the autowire.
Am I misunderstanding how to do this? How can I specify that I want JMockit to autowire using my MockUp<> implementation?

I'm new too but I think something like this would work in your case...
This will mock the ResultsAPIWrapper() and not initialize any static variables and create a specific mock for load():
new MockUp<ResultsAPIWrapper>() {
#Mock
void $clinit() {
//disable static initialization
}
#Mock
public String load() {
return "done";
}
};

Related

How to mock a member in the Class that you spy with powermockito

How can I mock a member class in another class which has already been spied by PowerMockito.spy()?
#Component
public class BoxFileDao {
#Autowired
private BoxFileService boxFileService;
public void uploadFile() {
.....
boxFileService.uploadFile(user, credential);
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(BoxFileDao.class)
public class BoxFileDaoTest {
#Test
public void testUploadFile() {
BoxFileDao mock = PowerMockito.spy(new BoxFileDao());
(how do I get the boxFileService from mock?)
mock.uploadFile();
verify(boxFileService).uploadFile(user, credential);
}
}
You can use #InjectMock to inject the mocked boxFileService object in the real boxFileDao object. Your test class can be written something like
#RunWith(PowerMockRunner.class)
public class BoxFileDaoTest {
#Mock
private BoxFileService boxFileService;
#InjectMocks
private BoxFileDao boxFileDao;
#Test
public void testUploadFile() {
boxFileDao.uploadFile();
verify(boxFileService).uploadFile(user, credential);
}
}
First you create your class under test BoxFileDao while injecting the mock for boxFileService into it. Afterwards you can create the spy on it.
For example:
BoxFileDao dao = new BoxFileDao();
dao.boxFileService = Mockito.mock(BoxFileService.class);
BoxFileDao spy = Mockito.spy(dao);
But the question would be why do you even want to do that? Is there a reason to spy on BoxFileDao, your class under test?

Mockito when isn't replacing original method behaviour

I got 2 modules User and Email, both of them have 1 entry point which is a facade, rest is package scoped. The configuration is done in 2 classes
#Configuration
class UserConfiguration {
#Bean
UserFacade userFacade(UserRepository repository, EmailFacade emailFacade) {
return new UserFacade(repository, emailFacade);
}
}
#Configuration
class EmailConfiguration {
#Bean
EmailFacade emailFacade(EmailSender emailSender) {
return new EmailFacade(emailSender);
}
}
Now, I want to write tests that don't require Spring to start. I implemented a simple InMemoryRepository to make this happen
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade = new EmailFacade(new FakeEmailSender());
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I need some fake objects to instantiate EmailFacade so I wrote fake implementation
public class FakeEmailSender implements EmailSender {
#Override
public void sendEmail(EmailMessage emailMessage) throws RuntimeException {
}
}
In that scenario, I'm testing User domain, so I want to mock Email anyways.
I wrote a test to check if it works
#Test
public void shouldReturnSendingFailed() {
Mockito.when(emailFacade.sendUserVerificationEmail(Mockito.any())).thenReturn(Either.left(EmailError.SENDING_FAILED));
assertThat(userFacade.registerNewUser(RegisterUserDto.builder()
.username(USERNAME_4)
.email(VALID_EMAIL)
.password(VALID_PASSWORD).build()).getLeft(), is(EmailError.SENDING_FAILED));
}
But it isn't... after running this test I got
java.util.NoSuchElementException: getLeft() on Right
edit#
regiserNewUser() method
Either<DomainError, SuccessMessage> register(RegisterUserDto registerUserDto) {
if(userRepository.findUser(registerUserDto.getUsername()).isPresent())
return Either.left(UserError.USERNAME_ALREADY_EXISTS);
var userCreationResult = User.createUser(registerUserDto);
var savedUser = userCreationResult.map(this::saveUser);
var emailDto = savedUser.map(this::createVerificationEmail);
return emailDto.isRight() ? emailFacade.sendUserVerificationEmail(emailDto.get())
: Either.left(emailDto.getLeft());
}
Edit2#
With following test configuration
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I got nullpointer here, last line of registerNewUser().
Try running this code
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
private UserFacade userFacade;
#Before
public void setUp() {
userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
}
}
There are a few issues with your code:
You initialize your mocks twice. You don’t need to call initMocks in the setUp method if you are using Mockito runner
You are trying to inject mocks to already initialized object. But the field you are trying to inject is also passed to the constructor. Please read #InjectMocks doc, to check the strategies used to inject the mocks:
constructor (not used here, already initialized object)
setter (do you have one?)
field (is it not final)
There are details to each strategy (see my questions above). If no staregy is matched, Mockito will fail silently. The fact that you are passing an object in constructor, and rely on setter or field injection afterwards makes this code unnecesarily complex.

How do I inject dependencies in controller tests?

This is my class and its constructor and the dependencies.
public class FavouriteProfilesController extends BaseController implements CurrentUser, JsonHelper {
private final UserProvider userProvider;
private MessagesApi msg;
#javax.inject.Inject
public FavouriteProfilesController(
UserProvider userProvider,
MessagesApi msgApi) {
this.userProvider = userProvider;
this.msg = msgApi;
}
// methods etc...
This is the test code I just copied from the docs:
public class FavouriteProfilesControllerTest extends WithApplication {
#Override
protected Application provideApplication() {
return new GuiceApplicationBuilder()
.configure("play.http.router", "javaguide.tests.Routes")
.build();
}
#Test
public void testIndex() {
Result result = new FavouriteProfilesController().index(); // Inject dependencies here
assertEquals(OK, result.status());
assertEquals("text/html", result.contentType().get());
assertEquals("utf-8", result.charset().get());
assertTrue(contentAsString(result).contains("Welcome"));
}
}
The controller has 2 dependencies, UserProvider and MessagesApi, how do I inject/mock them into the controller test?
If you use Mockito, you can mock them like this:
#RunWith(MockitoJUnitRunner.class)
public class FavouriteProfilesControllerTest extends WithApplication {
#InjectMocks
private FavouriteProfilesController controller;
#Mock
private UserProvider userProvider;
#Mock
private MessagesApi msg;
#Test
public void test() {
Assert.assertNotNull(userProvider);
Assert.asserNotNull(msg);
}
}
The solution depends on what you intend to test. If you mean to mock the whole behavior of UserProvider and MessageApi, using Mockito may be a proper solution.
In case you want to test controller functionality with real objects, you need to inject real objects. This may be done like this:
public class FavouriteProfilesControllerTest extends WithApplication {
#Test
public void testIndex() {
running(Helpers.fakeApplication(), () -> {
RequestBuilder mockActionRequest = Helpers.fakeRequest(
controllers.routes.FavouriteProfilesController.index());
Result result = Helpers.route(mockActionRequest);
assertEquals(OK, result.status());
assertEquals("text/html", result.contentType().get());
assertEquals("utf-8", result.charset().get());
assertTrue(contentAsString(result).contains("Welcome"));
});
}
}
Using of GuiceApplicationBuilder is not necessary, if you do not mean to use different injection binding for your test. Call to Helpers.fakeApplication() invokes the default dependency injection.
You can find more about unit testing in Play here.

Using #InjectMocks to replace #Autowired field with a mocked implementation

I want to replace an autowired class of a service in my spring boot app with a mocked implementation of that class that I created specifically for testing.
I chose to create this mocked implementation because the behaviour of this class is too complicated to mock using mockito as it requires multiple other mocks itself.
I am not able to work out how to inject this mocked implementation into the service.
Here is a minimal example of the situation:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest{
#Autowired
ComplicatedDependency complicatedDependency;
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class MockComplicatedDependency implements ComplicatedDepencency{
public MockComplicatedDependency(...){
// Inject other mocked objects into this mock
}
public String doSomthing(){
// This would be a mocked version of this function for testing
return "test";
}
}
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService(){
#InjectMock
private static ServiceIWantToTest serviceIWantToTest = new ServiceIWantToTestImpl();
#Mock
ComplicatedDependency mockComplicatedDependency;
#BeforeClass
public static void init(){
mockComplicatedDependency = new MockComplicatedDependency(...);
}
#Test
public void testAttempt(){
serviceIWantToTest.methodUsingDependency(); // This method calls complicatedDependency.doSomething() which does not run the mocked version in MockComplicatedDependency which I wanted to inject, and would always return null instead of the "test" string I put in this example.
}
}
Do you have to use Mockito annotations to setup dependencies for the class under test?
If that is not the main constraint why not just do the plain simple setup and introduce a constructor or a setter in ServiceIWantToTestImpl class for the ComplicatedDependency field and set the dependency in your test setup directly to whatever impl of ComplicatedDependency you like e.g.:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest {
#Autowired
ComplicatedDependency complicatedDependency;
public ServiceIWantToTestImpl() {
}
public ServiceIWantToTestImpl(ComplicatedDependency complicatedDependency) {
this.complicatedDependency = complicatedDependency;
}
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class TestingTheService {
private static ServiceIWantToTestImpl serviceIWantToTest;
#BeforeClass
public static void init(){
serviceIWantToTest = new ServiceIWantToTestImpl(new MockComplicatedDependency());
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
That is one way.
To make it work with Mockito, You could to use #Spy instead of #Mock like this:
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService {
#InjectMocks
private static ServiceIWantToTestImpl serviceIWantToTest = new ServiceIWantToTestImpl();
#Spy
private static ComplicatedDependency complicatedDependency = new MockComplicatedDependency();
#BeforeClass
public static void init() {
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
Though this is a bit of a hack. I strongly recommend that you read the JavaDoc of the #Spy annotation and make sure it's expected use is what you really need for your test.

Inject mocks to Abstract class using mockito

I am mocking an abstract class like below:
myAbstractClass = Mockito.mock(MyAbstractClass.class, Mockito.CALLS_REAL_METHODS);
the problem is that MyAbstractClass has some dependencies injected via EJB annotations and there are not setters. Is there a way to inject the dependencies?
#InjectMocks does not work with Abstract classes.
I am using junit5 for this.
What I did is instantiate the abstract class with a new abstractClass() in #BeforeEach and call the methods by super if the method is not abstract(using this because I have protected methods), after this I use ReflectionUtils.setField() to set the mocks in the abstract class and test every method and works pretty well. I leave a simple example that works.
AbstractClass
public abstract class AbstractClass {
#Autowired
private Environment environment;
protected String getProperty(String property){
return environment.getRequiredProperty(property);
}
}
AbstractClassTest
#ExtendWith(MockitoExtension.class)
class AbstractClassTest {
AbstractClass abstractClass;
#Mock
Environment environment;
#BeforeEach
void setUp() {
abstractClass = new AbstractClass() {
#Override
public String getProperty(String property) {
return super.getProperty(property);
}
};
ReflectionTestUtils.setField(abstractClass, "environment", environment);
}
#Test
void shouldReturnProperty() {
String propertyValue = "this property";
when(environment.getRequiredProperty("property")).thenReturn(propertyValue);
String property = abstractClass.getProperty("property");
assertEquals(propertyValue, property);
}
}
This is just using mockito and junit5 to test.
Remember to call ReflectionUtils after you instantiate the class with new AbstractClass() or the mocks won't be injected.
Any improve on this implementation is welcome :D.
Since you cannot instantiate an Abstract class there is nothing to test. I would recommend that you create child class (it could be a nested class inside your test class), and then run your tests that way. Then you can use the #Mock, #InjectMocks as you would normally.
You can use the Powermock library to inject mocks in myAbstractClass using Whitebox.setInternalState(myAbstractClass, mock(MockedClass.class));
Junit 4 specific solution
Abstract class that need to be tested
#Slf4j
public abstract class AdhocNotificationEmail {
#Autowired
protected CustomerNotificationRepository customerNotificationRepository;
protected abstract Map<String, String> abstractMethod(AdhocNotificationDTO adhocNotificationDTO);
public JSONObject concreteMethod(){
// some stuff that needs to be tested and common to all subclasses
}
}
Test Class:
#RunWith(SpringJUnit4ClassRunner.class)
public class AdhocNotificationEmailTest{
#Mock
protected CustomerNotificationRepository customerNotificationRepository;
private AdhocNotificationEmail unit;
#Before
public void setUp() {
unit = new AdhocNotificationEmail() {
#Override
protected Map<String, String> abstractMethod(AdhocNotificationDTO notificationDTO) {
return null;
}
};
unit.customerNotificationRepository = customerNotificationRepository;
}
#Test
public void concreteMethod_greenPath() {
final String templateName = "NOTIFICATION_TEMPLATE";
final AdhocNotificationDTO adhocNotificationDTOStub = getAdhocNotificationDTOStub(templateName);
final CustomerNotification customerNotificationStub = getCustomerNotificationStub(templateName);
when(customerNotificationRepository.findByIdAndTemplateName(id, templateName)).thenReturn(customerNotificationStub);
final JSONObject response = unit.concreteMethod(adhocNotificationDTOStub);
assertNotNull(response);
}
Personally, what I like to do is to extend the abstract with an anonymous class declared in the #Before (or #BeforeEach in junit.jupiter). This way I can achieve the following:
Don't mock the class that I want to test (like you are doing with Mockito.mock(MyAbstractClass.class, Mockito.CALLS_REAL_METHODS)), since that is kind of an anti-pattern. You only want to Mock the dependencies of the class you are testing;
You can provide Mocks for the dependencies of the abstract class, and that are called by non-abstract methods;
You can test non-abstract methods that call abstract methods
Example:
class TestAbstractClass {
#Mock
private ServiceDependency dependency;
private AbstractClass abstractClass;
#BeforeEach
void setUp() {
abstractClass= new AbstractClass (dependency) { };
}
#Test
void test(){
Mockito.when(dependency.someMethod()).thenReturn(something);
var result = abstractclass.someNonAbstractMethod();
// assertions
}
}
Good practice is to write unit tests for all possible classes which inherits from this abstract class. Because in theory it is possible situation. This dependency should be mocked and you should forget about mocking dependencies of this EJB component.
Maybe some code snippets would help to clarify what you try to achieve here.

Categories

Resources