How to inject certain properties values during junit to a specific test - spring-boot

My Spring Boot app has some test that are reading their properties from the application.yml that is in the test folder.
cat:
maxAge:30
maxNameSize:10
all is working fine, but I like that in certain tests, other values will be injected:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {
Cat.class
})
#SpringBootTest
public class CatTest {
#Test
public void testX(){
//inject maxAge=90
// use maxNameSize from the application.yml
....
#Test
public void testZ(){
//inject maxNameSize=5
// use maxAge from the application.yml
....
}

Changing properties on method level is not supported by Spring at this moment.
You can use nested classes to accomplish this.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {
Cat.class
})
#SpringBootTest
public class CatTest {
#Nested
#SpringBootTest(properties = "cat.maxAge=90")
public class NestedTestX {
#Test
void testX() {
//noop
}
}
#Nested
#SpringBootTest(properties = "cat.maxNameSize=5")
public class NestedTestZ {
#Test
void testZ() {
//noop
}
}
}

Related

Is it possible to override Spring bean in JUnit #Nested class?

I can't find an elegant solution for overriding a property inside the Junit #Nested class.
What I wanted to achieve is to have something like the following:
#SpringBootTest
#NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.OVERRIDE)
class EnclosingClassTest {
#Test
void testA() {
...
}
#Nested
class NestedClassTest {
#TestConfiguration
static class InnerConfig {
#Bean
public ABean aBean() {
...
}
}
#Test
void testB() {
// Want use overridden ABean
...
}
}
}
Any help is much appreciated.

Why did #TestConfiguration not create a bean for my test?

My service
#Service
public class StripeServiceImpl implements StripeService {
#Override
public int getCustomerId() {
return 2;
}
}
My test
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}
The error: java.lang.NullPointerException. I had checked and the stripeService is actually null.
Since you are autowiring you need an applicationcontext so that Spring can manage the bean and then can get injected in your class. Therefore you are missing an annotation to create the applicationcontext for your testclass.
I have updated your code and it works now(with junit 5 on your classpath). In the case dat you are using junit 4 it should be #RunWith(SpringRunner.class) instead of #ExtendWith(SpringExtension.class):
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfiguration.class)
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}

How to set and inject property Value from Test in Junit

My Service class uses a property set it application.properties
#Service
public class Service {
#Value("${my.prop}")
private String prop;
public Response doWork(String param1,String param2){
System.out.println(prop); //NULL!!!
}
}
I want to test it and set my own value:
Test Class:
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource(locations = "application.properties",properties = { "my.prop=boo" })
public class ServiceUnitTest {
#InjectMocks
private Service service;
#Test
public void fooTest(){
Response re = service.doWork("boo", "foo");
}
}
But when I run the test, the value is null (not even the value that exists in application.properties).
I don't have experience with MockitoJUnitRunner, but I am able to achieve this using PowerMockRunner.
Set up the application context with a test configuration, and autowire the bean from you application context into your test class. You also shouldn't need the "locations = " bit in the #TestPropertySource annotation.
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringRunner.class)
#TestPropertySource(properties = { "my.prop=boo" })
public class ServiceUnitTest {
#TestConfiguration
static class ServiceUnitTestConfig {
#Bean
public Service service() {
return new Service();
}
}
#Autowired
Service service;
#Test
public void fooTest(){
Response re = service.doWork("boo", "foo");
}
}

Cannot Mock an Injected Dependency in Controller Constructor

I am having a problem with mocking an object being injected in to a controller.
I am running an integration test. In my test I have the following setup:
#RunWith(SpringRunner.class)
#SpringBootTest
public class AuthenticationTests {
#TestConfiguration
public class Config {
#Bean
#Primary
public AbstractClient client() {
return new AbstractClient() {
#Override
public ManagedChannel getChannel() {
return new ManagedChannel();
}
};
}
}
}
In the controller being tested, AbstractClient is dependency injected like so:
#Controller
public class MyController {
private ManagedChannel managedChannel;
public MyController(AbstractClient client) {
managedChannel = client.getChannel();
}
}
Whenever I run the test, AbstractClient defined in the #TestConfiguration class is never injected - instead the default one is (which is annotated as #Service).
Can anyone help?

test suite inside spring context

Is it possible to run test suite with loaded spring context, something like this
#RunWith(Suite.class)
#SuiteClasses({ Test1.class, Test2.class })
#ContextConfiguration(locations = { "classpath:context.xml" }) <------
public class SuiteTest {
}
The code above obviously wont work, but is there any way to accomplish such behavior?
This is currently how spring context is used in my test suite:
#BeforeClass
public static void setUp() {
final ConfigurableApplicationContext context =
loadContext(new String[] { "context.xml" });
jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
// initialization of other beans...
}
I have tried you code, the test suite are running with spring context loaded. Can you explain in more detail what the problem is?
here is the code:
#RunWith(Suite.class)
#SuiteClasses({ Test1.class, Test2.class })
public class SuiteTest {
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:context.xml" })
#Transactional
public class Test1 {}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:context.xml" })
#Transactional
public class Test2 {}
If you want Suite class to have its own application context, try this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:context.xml" })
#Transactional
public class SuiteTest {
#Test public void run() {
JUnitCore.runClasses(Test1.class, Test2.class);
}
}

Resources