I'm trying to mock a private field in my class which is being initialized by OSGI container in which my app is running. I'm putting a sample code for reference, any clue on this please:
import org.apache.felix.scr.annotations.*
#Component (name = "MyServiceImpl ", ds = true, immediate = true)
#Service
public class MyServiceImpl extends MyBasee implements MyService {
#Reference (name = "MyOtherService", bind = "bind", unbind = "unbind", policy = ReferencePolicy.STATIC)
private MyOtherService myServiceRegistryConsumer;
}
Here I'm trying to mock private field MyOtherService myServiceRegistryConsumer
With Mockito you can mock and inject fields using the #InjectMocksannotation.
#RunWith(MockitoJUnitRunner.class)
public class AppTest {
#Mock
private MyOtherService myServiceRegistryConsumer;
#InjectMocks
private MyServiceImpl myServiceImpl;
#Test
public void testSomething() {
// e.g. define behavior for the injected field
when(myServiceRegistryConsumer.methodA()).thenReturn(/* mocked return value */);
}
}
Related
So I have this class (used lombok):
#RequiredArgsConstructor
#Service
public class ServiceImpl {
private final BookService bookService;
#Autowired
private TableService tableService;
public void method() {
if (!bookService.isEmpty()) return;
Object table = tableService.getObject();
}
}
My test class:
#ExtendWith(MockitoExtension.class)
#RunWith(JUnitPlatform.class)
public class ServiceImplTest {
#Mock BookService bookService;
#Mock TableService tableService;
#InjectMocks ServiceImpl serviceImpl;
#Test
public void testMethod() {
when(bookService.isEmpty()).thenReturn(true);
when(tableService.isEmpty()).thenReturn(new Object());
serviceImpl.method();
}
}
If I run it, the bookService is null. It is not injected in the class. When the code is at the if (!bookService.isEmpty()) return; the bookService is null.
if I change my testMethod to this:
#Test
public void testMethod() {
MockitoAnnotations.initMocks(this);
when(bookService.isEmpty()).thenReturn(true);
when(tableService.isEmpty()).thenReturn(new Object());
serviceImpl.method();
}
So I added MockitoAnnotations.initMocks(this); then the code Object table = tableService.getObject(); in my class returns null. So the tableService is not null, but the getObject() return null;
Any idea how to fix it? I am not let to change the class code.
Thanks in advance.
I have following component:
#Component
public class ServiceManagerImpl implements ServiceManager {
private final ServiceA serviceA;
private final ServiceB serviceB;
private final String path;
#Autowired
protected ServiceManagerImpl(ServiceA serviceA, ServiceB serviceB, String path) {
this.serviceA= serviceA;
this.serviceB= serviceB;
this.path= path;
}
(...)
}
Now I want to create simple service to which I will inject above component with specific path value. This value should come from class with String constans:
#Component
public class ServiceManagerClientImpl implements ServiceManagerClient {
private ServiceManager serviceManager;
#Autowired
public ServiceManagerClientImpl(ServiceManager serviceManager) {
this.serviceManager = serviceManager;
}
}
Is it possible to dynamically inject simple path values on ServiceManagerClientImpl level (not from properties / yaml files)?
You can autowire the Environment class
import org.springframework.core.env.Environment;
#Autowired
private Environment environment;
You can read the enironment variable("path" in your case) using the below statement.
environment.getProperty("path");
I'm developing a Java Spring application. I have some fields in my application which are configured using a .yml config file. I would like to import those values using an #Value annotation on the fields in question. I would also like to use the best-practice of constructor injection rather than field injection, but I would like to write my constructor using Lombok rather than manually. Is there any way to do all these things at once? As an example, this doesn't work but is similar to what I want to do:
#AllArgsConstructor
public class my service {
#Value("${my.config.value}")
private String myField;
private Object myDependency;
...
}
In this case, what I want is Lombok to generate a constructor which sets only myDependency, and for myField to be read from my config file.
Thanks!
You need #RequiredArgsConstructor and mark myDependency as final. In this case, Lombok will generate a constructor based on 'required' final filed as argument, for example:
#RequiredArgsConstructor
#Service
public class MyService {
#Value("${my.config.value}")
private String myField;
private final MyComponent myComponent;
//...
}
That is equal the following:
#Service
public class MyService {
#Value("${my.config.value}")
private String myField;
private final MyComponent myComponent;
public MyService(MyComponent myComponent) { // <= implicit injection
this.myComponent = myComponent;
}
//...
}
Since here is only one constructor, Spring inject MyComponent without the explicit use of the #Autowired annotation.
Male sure you are using at least version 1.18.4 of Lombok. And that you have your desired annotation added to the lombok.config file.
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value
Here is your class:
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class MyService{
#Value("${my.config.value}")
private String myField;
private Object myDependency;
}
And here is the lombok generated class:
public class MyService {
#Value("${my.config.value}")
private String myField;
private Object myDependency;
#Autowired
#Generated
public MyService(#Value("${my.config.value}") final String myField, final Object myDependency) {
this.myField = myField;
this.myDependency = myDependency;
}
PS: Make sure you have the lombok.config file under /src/main/java folder. I tried adding it to /src/main/resources and it did not work.
Response taken from here.
Is it possible to just ignore/mock any injected dependencies inside a MockedBean?
Example:
#Service
public class MyService {
#Autowired
private MailerService mailer;
public void test1() {
//does not use mailer
}
public void test2() {
//...
mailer.send();
}
}
#Service
public class MailerService {
//I want these to be automatically mocked without explicit declaration
#Autowired
private JavaMailSender sender;
#Autowired
private SomeMoreService more;
//also these should be mocked without having to provide properties
#Value("${host}") private String host;
#Value("${user}") private String user;
#Value("${pass}") private String pass;
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class MyServiceTest {
#Autowird
private MyService myservice;
#MockBean
private MailserService mailer;
#Test
public void test1() {
myservice.test1();
}
}
I could use #MockBean to sort out mailer injection dependency. But any service inside the mocked bean would also have to be explicitly mocked.
Question: is it possible to mock a service "away". Means, just mock the bean and don't care what's inside the #MockedBean (or automatically also mock anything inside #MockedBean)?
As for me the best way to inject mocks is to use MockitoJUnitRunner
#RunWith(MockitoJUnitRunner.class)
public class MocksTests {
#InjectMocks
private ParentService parent;
#Mock
private InnerService inner; // this will be injected into parent
//your tests
}
I have a bit of mess with Mockito and fields annotated with #Spy .
I want to test this class:
#Service
public class CategoryServiceImpl implements CategoryService {
#Autowire
private CategoryRepository categoryRepository;
private BoundMapperFacade<CategoryDTO, Category> boundMapper;
#Autowired
public void createMapper(final Mapper mapper) {
boundMapper = mapper.getMapperFactory().getMapperFacade(
CategoryDTO.class, Category.class);
}
// Rest of methods...
}
So, I have created a testing class as shown below:
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
#Spy
private BoundMapperFacade<CategoryDTO, Category> boundMapper;
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
// Rest of methods...
}
When Mockito instances categoryServiceImpl injects categoryRepository as a mock class but it does not know how to create boundMapper. This class depends on mapper, so I have rewritten my code:
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
private BoundMapperFacade<CategoryDTO, Category> boundMapper = spy(mapper.getMapperFactory().getMapperFacade(
CategoryDTO.class, Category.class));
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
// Rest of methods...
}
But now the problem is the creation of boundMapper is executed before Mockito injects mapper, so I get a NullPointerException.
So, is there any way to create an spy class who depends on another one and finally inject this last one in a field tagged as #InjectMocks?
If you have a spy that depends on a mock or a spy, the only way I've seen to do it is inside the #Before decorated function.
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
private BoundMapperFacade<CategoryDTO, Category> boundMapper = ;
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
#Before
public void setup() {
boundMapper = spy(mapper
.getMapperFactory()
.getMapperFacade(CategoryDTO.class, Category.class)
);
}
// Rest of methods...
}
I'm not sure how this works with #InjectMocks, so that might be something to look into. There might be a non-decorator version of it that you can run after boundMapper is initialized if CategoryServiceImpl is dependent on it.