How to mock method of Injected service in Spring Integration Tests - spring

I have following service class, that I want to test
#Service
public class MasterService {
#Inject
private ServiceOne serviceOne;
#Autowired
private ServiceTwo serviceTwo;
#Inject
private ServiceThree serviceThree;
#VisibleForTesting
void execute() {
if (serviceThree.isFlag()) {
....
}
}
I am testing execute() method. I want to mock serviceThree.isFlag() to return true. Following is my test.
public class MasterServiceIT{
#Inject
private MasterService masterService;
#Inject
private ServiceThree serviceThree;
#Test
public void testMasterService() {
when(serviceThree.isFlag()).thenReturn(true); <---- this never works
masterService.execute();
}
}
However, it never retrieves true. Any remarks? I wanted to use #InjectMocks Then can I inject only this service which I mocked? or I need to mock each service if I am using #InjectMocks

Are you sure that you need to mock for an integration test? Well, sometimes there are cases when we need to mock some service which refers to some external services like SharePoint, etc. Well if you need to mock so in this case you need to mock spring service bean in spring context. You can do it via #MockBean

Related

how to use junit and mockito when we have a mulit layer service call approach in a restfull web service

i am using spring tool suite to write a code .there are 4 layers restContoller,buisnesslogic,domain ,service....
i want to test for a method of business logic layer where it calls a method of dao which finally calls a method of service layer to return a simple primitive value... to make it clear in the businesslogic class i have autowired domain class ,and in the domain class i have autowired the service classs..the problem that i am facing iss when i run the test class i am getting NullPointerException i am attaching the code for the test class... kindly help if possible
#ExtendWith(MockitoExtension.class)
class CustomerBlTest {
#Mock
CustomerService mockService;
#Autowired
CustomerDO customerDo;
#Autowired
#InjectMocks
CustomerBl bl; //buisnesslogic class
#Test
void checkForGetInteger() {
when(mockService.getIntegerFfromService()).thenReturn(3);
int actual = bl.getInteger();
Assertions.assertEquals(3, actual);
}
}
Since you are extending MockitoExtension hence this test class is not aware of spring. But you are still using #Autowired annotation. So that's wrong. Remove all #AUtowired annotations in the test class. Besides this you do not need to bring in all the sterotyped classes. Bring in only the one that the class is using i.e. in your case the classes injected in CustomerBl class. I think that should be CustomerService class. So remove the CustomerDO class if it's not being used in CustomerBl class. The #InjectMock and #MOck annotation have been applied correclty. I think that should help you get your result.
You need to use #Mock instead of #Autowired as shown below.
#ExtendWith(MockitoExtension.class)
class CustomerBlTest {
#Mock
CustomerService mockService;
#Mock
CustomerDO customerDo;
#InjectMocks
CustomerBl bl; //buisnesslogic class
#Test
void checkForGetInteger() {
when(mockService.getIntegerFfromService()).thenReturn(3);
int actual = bl.getInteger();
Assertions.assertEquals(3, actual);
}
}

Spring Web Service Test with MongoDB

I'm writing service tests for my Spring Boot Web application that acts as an interface to MongoDB. Ideally, my service test will test each component of my Spring application before finally hitting a Mocked MongoTemplate. The following code uses a MockMvc to hit my web endpoints.
#RunWith(SpringRunner.class)
#WebMvcTest(MyController.class)
#AutoConfigureDataMongo
public class MyControllerServiceTest {
#Autowired
private MockMvc mvc;
#Autowired
private MongoTemplate mongoTemplate
#SpyBean
private MyMongoRepository myMongoRepository;
#Test
public void createTest() {
MyObject create = new MyObject()
given(this.myMongoRepository.insert(create));
this.mvc.perform(post("localhost:8080/myService")...)...;
}
}
MyController contains an #Autowired MyMongoRepository, which in turn implements MongoRepository and necessitates a mongoTemplate bean. This code executes properly only if a running MongoDB instance can be found (this example is more of an integration test between my service and MongoDB).
How can I mock out MongoTemplate while still using my MockMvc?
You need to add the following line to your test unit:
#MockBean
private MongoTemplate mongoTemplate;
For example, your class should look like this:
#RunWith(SpringRunner.class)
#WebMvcTest(MyController.class, excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class MyMvcTests {
#Autowired
private MockMvc mvc;
#MockBean
private MyRepository repository;
#MockBean
private MongoTemplate mongoTemplate;
#Test
public void someTest() {}
}
You can find a complete Spring Boot application that include Integration and Unit tests here.
I think a better approach to test would be to test your web layer(controller) and your service layer separately.
For testing your web layer you can use MockMvc and you can mock your service layer.
For testing your service layer which in turn talks to mongo, you can use a Fongo and nosqlunit.
Some examples here
https://arthurportas.wordpress.com/2017/01/21/sample-project-using-spring-boot-and-mongodbfongo-and-test-repository-with-nosqlunit/
https://github.com/JohnathanMarkSmith/spring-fongo-demo

Cannot inject #Service in Unit Test in SpringBoot project

i have a #Service that I am trying to mock in an Unit Test but i get a null value so far. In the application class I specify what are the scanBasePackages. Do I have to do this in a different way? Thanks.
This is my service class that implements an interface:
#Service
public class DeviceService implements DeviceServiceDao {
private List<Device> devices;
#Override
public List<Device> getDevices(long homeId) {
return devices;
}
}
This is my unit test.
public class SmartHomeControllerTest {
private RestTemplate restTemplate = new RestTemplate();
private static final String BASE_URL = “..”;
#Mock
private DeviceService deviceService;
#Test
public void getHomeRegisteredDevices() throws Exception {
Device activeDevice = new DeviceBuilder()
.getActiveDevice(true)
.getName("Alexa")
.getDeviceId(1)
.getHomeId(1)
.build();
Device inativeDevice = new DeviceBuilder()
.getInactiveDevice(false)
.getName("Heater")
.getDeviceId(2)
.getHomeId(1)
.build();
UriComponentsBuilder builder = UriComponentsBuilder
.fromUriString(BASE_URL + "/1/devices");
List response = restTemplate.getForObject(builder.toUriString(), List.class);
verify(deviceService, times(1)).getDevices(1);
verifyNoMoreInteractions(deviceService);
}
You have to use a Spring test runner if you want to load and use a Spring context during tests execution.
You don't specify any runner, so it uses by default the runner of your test API. Here is probably JUnit or TestNG (the runner using depends on the #Test annotation specified).
Besides, according to the logic of your test, you want to invoke the "real"
REST service :
List response = restTemplate.getForObject(builder.toUriString(),
List.class);
To achieve it, you should load the Spring context and load the Spring Boot container by annotating the test with #SpringBootTest.
If you use a Spring Boot context, to mock the dependency in the Spring context, you must not use #Mock from Mockito but #MockBean from Spring Boot.
To understand the difference between the two, you may refer to this question.
Note that if you are using the #SpringBootTest annotation, a TestRestTemplate is automatically available and can be autowired into your test.
But beware, this is fault tolerant. It may be suitable or not according to your tests.
So your code could look like :
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SmartHomeControllerTest {
private static final String BASE_URL = “..”;
#Autowired
private TestRestTemplate restTemplate;
#MockBean
private DeviceService deviceService;
#Test
public void getHomeRegisteredDevices() throws Exception {
...
}
As a side note, avoid using raw type as List but favor generic type.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = NotificationApplication.class)
public class EmailClientImplTest {
...
}
And also add the needed properties/configs in
/src/test/resources/application.yml
Good luck!
I figured it out, I am using Mockito and used that to annotate my test class. This allowed me to get a mock of the service class that i am trying to use.
#RunWith(MockitoJUnitRunner.class)
public class SmartHomeControllerTest {..
#Mock
private DeviceService deviceService;
}
Try with #InjectMock instead of #Mock
You should run your test with spring boot runner

Spring HATEOAS Resource assembler is not instantiated in unit test

I am trying to write a unit test for a REST controller which generates HATEOAS links via Resource assembler class. Everything is OK in production, but with the unit test Resource assembler class is not being injected into the controller.
my resource assembler class is:
#Component
public class ModelResourceAssembler extends ResourceAssemblerSupport<Model, ModelResource> {
public ModelResourceAssembler() {
super(ModelRestController.class, ModelResource.class);
}
#Bean
public ModelResourceAssembler modelResourceAssembler(){
return new ModelResourceAssembler();
}
#Override
public ModelResource toResource(Model model) {
...
}
}
The controller is:
#Controller
#RequestMapping("/demo")
#ComponentScan(basePackages = {"com.foo.demo"} )
public class ModelRestController {
#Autowired
private ModelPersistenceHandler modelPersistenceHandler;
#Autowired
private ModelResourceAssembler modelResourceAssembler;
...
}
And the unit test:
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes= {ModelResourceAssembler.class, ModelRestController.class})
public class ModelRestControllerTest {
private MockMvc mockMvc;
#InjectMocks
private ModelRestController modelRestController;
#Mock
private ModelPersistenceHandler modelPersistenceHandler;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(modelRestController).build();
}
...
}
No matter what I do the ModelResourceAssembler instance is always null. Since the application is Spring Boot it does not have the WebCoonfig classes and autowired WebApplicationContext is always null, so I cannot (and really don't want to since I am running a unit test) instantiate MockMvc via webAppContextSetup
The solution ended up being quite simple: I needed to add one line to my test:
#Spy
private ModelResourceAssembler modelResourceAssembler;
And the bean was instantiated and properly wired
In your example you use #InjectMocks but don't declare a mock for ModelResourceAssembler. You don't get an instance out of nowhere.
You use the MockitoJUnitRunner.class. It has no idea of Spring beans. For testing Spring applications you rather want to use SpringJUnit4ClassRunner.class.
If i may suggest, if you use constructor injection for your controller then you can just mock the dependency and not need spring junit test runner stuff.

setting mocked object in case of spring annotation

I'm writing unit test case using Junit, EasyMock and Spring. I'm trying to mock DAO layer call. I've used annotation to inject bean in my application
Service layer class:
public class CustomerService {
#Autowired
private CustomerDao customerDao;
........
public void findCustomerByAccountNumber(String accountNumber){
}
}
Test case for service method:
public class CustomerServiceTest extends AbstractContextConfigLoaderTest{
private CustomerDao mockCustomerDao;
private CustomerService customerService;
private String accountNumber="5247710009575432";
#Before
public void setUp(){
mockCustomerDao= EasyMock.createMock(CustomerDao.class);
customerService= new CustomerService();
}
if i would have used setter injection using Spring bean configuration, i would've set mocked dao object to customerService like below.
customerService.setCustomerDao(mockCustomerDao);
How can i do the same in case of Spring annotation ?
You can use still setup a method
protected void setCustomerDao(CustomerDao customerDao)
and only use it in your JUnit to set the mocked dependencies. The protected access will prevent any class that is not in the same package from using that method.
I suggest enabling spring in your test with something like #RunWith(SpringJUnit4ClassRunner.class) and #ContextConfiguration, in your spring context for the test
make the mock as spring bean.
<bean class="org.easymock.EasyMock" factory-method="createMock">
<constructor-arg value="some.package.CustomerDao" />
</bean>
Now should be wired to the CustomerService, to record the expected behavior you will need to wire the mock in your test class:
#Autowired
private CustomerDao mockCustomerDao;
#Autowired
private CustomerService customerService;
Why not expose this through the constructor and inject it that way? Your production code can use Spring and your test code can just instantiate the object directly.
At the moment you're at the mercy of your DI framework. Break that dependency.

Resources