How to Pass #Value to a #Component for Spring Unit Testing - spring

Im writing unit tests for services, controllers, etc however theres is a #Component that has the following values
#Component
Public class myclass
#Autowired
Private MyTemplate myTemplate
#Value("$someString")
Private String someString
#PostConstruct
Public void loadString()
...
How would I manually load values into the #Values? I have tried with Mocks, TestPropertySource, ReflectionTestUtils, among other ways found around

You can inject the #Value in test class by ReflectionTestUtils. Load container only in case of Controllers. For writing test cases for services and dao you don't need to load the spring container.
public class TestClass{
private #InjectsMock ServiceClass service;
#BeforeAll
public void setUp(){
ReflectionTestUtils.setField(service, "someString", "someValue");
}
//your test cases over here.
}

I can immediately think of two options
1) You could define $someString in your test/resources/test.properties
#RunWith(SpringRunner.class)
#TestPropertySource(locations="classpath:test.properties")
public class ClassTest {
}
2) do it manually
#RunWith(SpringRunner.class)
public class ClassTest {
#Autowired
private MyClass miclass;
#Before
public void setupObject() {
miclass.setProperty("someting");
}
}

Related

Testing Conditionally Initialized RestController based on active profile

I have the following class, which is loaded conditionally based on the profile. I want it to only load for assisting in lower environments and not production:
#RestController
#RequestMapping("/foo")
#Profile("!prod")
public class FooController {
private Bar bar;
#PostMapping
public ResponseEntity<?> createFoo(){
bar.something();
return new ResponseEntity<Object>(HttpStatus.ACCEPTED);
}
}
I would like to have the following tests for this class:
#WebMvcTest
#RunWith(SpringRunner.class)
#ActiveProfiles("prod")
public class FooControllerTest {
private MockMvc mockMvc;
#Mock
private Bar bar;
#InjectMocks
private FooController subjectUnderTest;
#Before
public void init(){
mockMvc = MockMvcBuilders
.standaloneSetup(subjectUnderTest)
.build();
}
#Test
public void givenProdProfile_whenCreateFoo_thenNotFoundResponseReturned() throws Exception {
doNothing().when(mockBar).something();
mockMvc.perform(MockMvcRequestBuilders
.post("/foo"))
.andExpect(status().isNotFound());
}
and then another test class to test this case, with #ActiveProfile('non-prod'):
givenNonProdProfile_whenCreateFoo_thenAcceptedResponseReturned
I am confused on how to properly test this. I've tried many different different approaches, and none of them seem to properly test the class. I've tried annotating my test class with #ActiveProfile, etc.
I suppose the crux of my question, is how can I test different profiles with MockMvc and Mockito?

Null is passed to autowired service even after mocking - SpringBootTest

I wanted to do integration testing of my API.
#RestController
#RequestMapping("/api/v1")
public class TestController {
#Autowired
TestService testService;
#RequestMapping("/welcome")
public String welcomeMessage(#RequestParam("name") String name) {
return testService.welcomeMessage(name);
}
}
Below are the service interface and its implementation:
public interface TestService {
public String welcomeMessage(String name);
}
public class TestServiceImpl implements TestService{
#Autowired
TestRepository repo;
#Override
public String welcomeMessage(String name) {
repo.save(new StringEntity(name));
return "Hello "+name;
}
}
Below is the Test Case:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class MockitoTestingApplicationTests {
#Autowired
MockMvc mvc;
#MockBean
TestService testService;
#MockBean
TestController testController;
#Test
public void contextLoads() throws Exception {
Mockito.when(testController.welcomeMessage(ArgumentMatchers.anyString())).thenCallRealMethod();
Mockito.when(testService.welcomeMessage(ArgumentMatchers.anyString())).thenCallRealMethod();
mvc.perform(get("/api/v1/welcome").param("name", "dude")).andExpect(status().isOk());
}
}
I have a few questions.
when I'm executing the above code it is throwing an error saying cannot call real method on abstract methods. And When I'm mocking the TestServiceImpl, It is throwing NullPointerException in the Controller because the TestService is null. How should I fix that?
How should I mock the repository layer when we are using MongoDB. when I try to Mock MongoTemplate, It is throwing an error saying MongoConvertor must not be null
Is this the right way to write test cases. can we have code coverage without using thenCallRealMethod()?
Please suggest me how to proceed. Thanks in advance.
Make sure you have an implementation of the service i.e. TestServiceImpl annotated with #Service (or #Component if it is not strictly a service) and use spying instead of mocking:
#SpyBean
TestService testService;
Spying by default call real methods so you have to mock these that implementation you do not want to call.
Regarding repositories, you should mock the components annotated with #Repository, not the actual SessionFactory / Template etc. that are used within.

autowired #components null in unit test

I have a class:
#Component
public class B {
#Autowired
private A a;
}
and A is a component:
#Component
public class A{}
In unit test class BTest:
public class BTest {
#Test
public void testBMethod() {
}
}
I am not using an xml to define context or for beans to be picked from.
What is the cleanest way I can get the test to run?
You don't have to use Spring for the unit tests. Mockito may be used for this.
public class BTest {
#Mock
private A a;
#Mock
private B b;
#Test
public void testBMethod() {
}
}
For more details, you may check https://springframework.guru/mocking-unit-tests-mockito/
and https://dzone.com/articles/use-mockito-mock-autowired

Unit Test with Spring JPA - #Autowired is not working

I have a unit test and a helper class.
Unfortunely the Helper class' autowire does not work.
It works fine in MyTest class.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath*:context.xml"})
#Component
public class MyTest {
#Autowired
private Something something1;
#Autowired
private Something something2;
..
#Test
public void test1()
{
// something1 and something2 are fine
new Helper().initDB();
..
}
}
// Same package
public class Helper {
#Autowired
private Something something1;
#Autowired
private Something something2;
..
public void initDB()
{
// something1 and something2 are null. I have tried various annotations.
}
}
I'd like to avoid using setters because I have like 10 of those objects and different tests have different ones.
So what is required to get #Autowired working in Helper class? Thx!
You must not create the Helper class by a new statement, but you have to let spring create it to become a spring been and therefore its #Autowired fields get injected.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath*:context.xml"})
#Component
public class MyTest {
#Autowired
private Something something1;
#Autowired
private Something something2;
..
#Autowired
private Helper helper
#Test
public void test1() {
helper.initDB();
}
}
//this class must been found by springs component scann
#Service
public class Helper {
#Autowired
private Something something1;
#Autowired
private Something something2;
public void initDB(){...}
}
Your Helper class is not instanciated by spring ... You have to add an annotation like #component (if you are using package scan), or you can define the class as Bean in your springconfiguration class. But if you create the instance by yourself, it doesn't work

How to access Spring context in jUnit tests annotated with #RunWith and #ContextConfiguration?

I have following test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/services-test-config.xml"})
public class MySericeTest {
#Autowired
MyService service;
...
}
Is it possible to access services-test-config.xml programmatically in one of such methods? Like:
ApplicationContext ctx = somehowGetContext();
This works fine too:
#Autowired
ApplicationContext context;
Since the tests will be instantiated like a Spring bean too, you just need to implement the ApplicationContextAware interface:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/services-test-config.xml"})
public class MySericeTest implements ApplicationContextAware
{
#Autowired
MyService service;
...
#Override
public void setApplicationContext(ApplicationContext context)
throws BeansException
{
// Do something with the context here
}
}
For non xml needs, you can also do this:
#RunWith(SpringJUnit4ClassRunner.class)
/* must provide some "root" for the app-context, use unit-test file name to the context is empty */
#ContextConfiguration(classes = MyUnitTestClass.class)
public class MyUnitTestClass implements ApplicationContextAware {
If your test class extends the Spring JUnit classes
(e.g., AbstractTransactionalJUnit4SpringContextTests or any other class that extends AbstractSpringContextTests), you can access the app context by calling the getContext() method.
Check out the javadocs for the package org.springframework.test.
It's possible to inject instance of ApplicationContext class by using SpringClassRule
and SpringMethodRule rules. It might be very handy if you would like to use
another non-Spring runners. Here's an example:
#ContextConfiguration(classes = BeanConfiguration.class)
public static class SpringRuleUsage {
#ClassRule
public static final SpringClassRule springClassRule = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Autowired
private ApplicationContext context;
#Test
public void shouldInjectContext() {
}
}

Resources