Write JUnit test on controller in SpringBoot Without start application - spring-boot

I am trying to test my controller method which is calling method of a dao class , now dao class has #Autowired repositry and method of dao class is also calling the repositry method.
I am ended up #mock repository in my test class too for mocking its behaviour.
test class:
Mock
UserRepository userRepository;
Mockito.when(userRepository.findByEmailId("abc#gmail.com")).thenReturn(obj);
dao class:
#Autowired
UserRepository userRepository;
obj=userRepository.findByEmailId(email);
now, my test case is not running. i am trying to create a base class for all the #Autowiring.
What should i do?

You don't need to mock UserRepository, but the DAO instead which is the direct dependency of your Controller. Something like the following:
#ExtendWith(SpringExtension.class)
#WebMvcTest(ControllerClassName.class)
public class ControllerClassNameTest {
#Autowired
protected MockMvc mvc;
#MockBean
private DaoClassName dao;
#BeforeEach
public void setUp() throws Exception {
Mockito.when(dao.whateverMethodYouWantToMock()).thenReturn(xyz);
}
// Your tests here
}
Keep in mind that you should test your Controllers with MockMvc to emulate a real HTTP call and not a direct method call. More information at https://www.baeldung.com/spring-boot-testing#unit-testing-with-webmvctest.

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

Controller layer test in SpringBoot application

I have a controller in my SpringBoot app:
#Controller
#RequestMapping("/v1/item")
public class Controller{
#Autowired
private ServiceForController service;
#PostMapping()
public String createItem(#ModelAttribute Item item) {
Item i = service.createItem(item.getName(), item.getDomain());
return "item-result";
}
}
And I'd like to test it separately from service with a help of mocks.How to implement it?
There are at least two approaches to do it:
To start up the whole SpringBoot context and make a sort of integration tests
Example:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class ControllerTest {
#Autowired
private MockMvc mvc;
#Test
#WithMockUser(roles = "ADMIN")
public void createItem() throws Exception {
mvc.perform(post("/v1/item/")
.param("name", "item")
.param("domain", "dummy.url.com"))
.andExpect(status().isOk());
//check result logic
}
Test exclusive controller layer and limit the whole loaded context exclusively to it. Example:
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = Controller.class)
public class ControllerTest{
#Autowired
private MockMvc mvc;
#MockBean
private ServiceForController service;
//testing methods and their logic
...
}
Even though the second approach seems more sensible (as for me) in terms of resources used, it may cause plenty of inconveniences due to the lack of beans initialized. For instance, before I decided to try another option, I faced the need to create mocks of at least 5 beans that are added to the context on SpringBoot start in my ContollerTest class.
Thus, I had to switch to the approach with a use of #SpringBootTest in combination with #SpyBean, that allowed me to call a Mockito verify() method.

How can I set Mockito `when` method when instantiating mock objects in Spring?

The method described in this answer best suits me for instantiating my mock objects.
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
However, I also need to set the Mockito when method(s).
Can I do that in the XML, or is the only way to to it like:
when( objectToBestTested.getMockedObject()
.someMethod(anyInt())
).thenReturn("helloWorld");
within my test case?
The reason I ask, is because I don't otherwise need a getter for MockedObject, and I'd only be adding a getter so I can test ObjectToBeTested.
This is the way of how I use Mockito with Spring.
Lets assume I have a Controller that use a Service and this services inject its own DAO, basically have this code structure.
#Controller
public class MyController{
#Autowired
MyService service;
}
#Service
public class MyService{
#Autowired
MyRepo myRepo;
public MyReturnObject myMethod(Arg1 arg){
myRepo.getData(arg);
}
}
#Repository
public class MyRepo{}
Code below is for the junit test case
#RunWith(MockitoJUnitRunner.class)
public class MyServiceTest{
#InjectMocks
private MyService myService;
#Mock
private MyRepo myRepo;
#Test
public void testMyMethod(){
Mockito.when(myRepo.getData(Mockito.anyObject()).thenReturn(new MyReturnObject());
myService.myMethod(new Arg1());
}
}
If you are using standalone applications consider mock as below.
#RunWith(MockitoJUnitRunner.class)
public class PriceChangeRequestThreadFactoryTest {
#Mock
private ApplicationContext context;
#SuppressWarnings("unchecked")
#Test
public void testGetPriceChangeRequestThread() {
final MyClass myClass = Mockito.mock(MyClass.class);
Mockito.when(myClass.myMethod()).thenReturn(new ReturnValue());
Mockito.when(context.getBean(Matchers.anyString(), Matchers.any(Class.class))).thenReturn(myClass);
}
}
I dont really like create mock bean within the application context, but if you do make it only available for your unit testing.

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.

Resources