I have an application.properties the values in which I am trying to autoWire in a bean
#Component
public class ConfigurationValues {
#Value("${my.host}") private String myHost
}
This works well when I run the application. However When I run a JUnit test, I get an error
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'my.host' in string value "${my.host}"
And this is my test code
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {Application.class})
public class AnotherDummyTest {
#Autowired
private ConfigurationValues configurationValues;
#Test
public void testValue() {
Assert.assertEquals("localhost", configurationValues.getMyHost());
}
}
This test case fails with the IllegalArgumentException that I mentioned.
Try this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class,
initializers = ConfigFileApplicationContextInitializer.class)
public class AnotherDummyTest {
Related
I have a problem of running my Test class. It returns "org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 't.c.i.s.se.Sfts' available: expected single matching bean but found 2: sftsImpl,sfts" this exception after I run it.
Here's my test class;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Sfta.class)
public class SftaTests {
#Autowired
ApplicationContext ac;
#Test
public void contextLoads() {
Sfts sfts= ac.getBean(Sfts.class);
assertTrue(Sfts instanceof SftsImpl);
}
}
And my other classes are like;
public interface Sfts {
public void process();
}
#Service
#Component
public class SftsImpl implements Sfts {
#Autowired
private GlobalConfig globalConfig;
#Autowired
private Ftr ftr;
private Fc fc;
#Async
#Scheduled(initialDelayString = "${s.f.t.m}", fixedRateString = "${s.f.t.m}")
public void process() {
int hod = DateTime.now().getHourOfDay();
if (hod != 6){
fc = new Fc(globalConfig, ftr);
fc.control();
}
}
}
Why I get the error after running the test application?
Try to remove #Component annotation from the SftsImpl bean.
#Service is enough to register a bean.
Also if you just want to test your bean - getting it from ApplicationContext maybe is not the best option.
Code example of a unit test without using ApplicationContext:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Sfta.class)
public class SftaTests {
#Autowired
Sfts sfts;
#Test
public void testAsync() {
sfts.process();
// do assertions here
}
}
I have an integration test class annotated with #SpringBootTest which starts up the full application context and lets me execute my tests. However I am unable to #Autowired beans into the test class itself. Instead I get an error:
No qualifying bean of type 'my.package.MyHelper' available".
If I do not #Autowire my helper class, but keep the code directly inside the setUp function, the test works as expected.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
public class CacheControlTest {
#Autowired
private MyHelper myHelper;
#Before
public void setUp() {
myHelper.doSomeStuff();
}
#Test
public void test1() {
// My test
}
}
How can I make use of Spring autowiring inside the test class while also using #SpringBootTest?
Following #user7294900 advice below, creating a separate #Configuration file and adding this at the top of CacheControlTest works:
#ContextConfiguration(classes = { CacheControlTestConfiguration.class })
However is there any way of keeping the configuration inside the CacheControlTest class itself? I have tried adding inside my test class:
public class CacheControlTest {
#TestConfiguration
static class CacheControlTestConfiguration {
#Bean
public MyHelper myHelper() {
return new MyHelper();
}
}
}
And
public class CacheControlTest {
#Configuration
static class CacheControlTestConfiguration {
#Bean
public MyHelper myHelper() {
return new MyHelper();
}
}
}
But they do not seem to have any effect. I still get the same error. The same configuration block works when placed in an separate file as mentioned above though.
Add ContextConfiguration for your Test Class:
#ContextConfiguration(classes = { CacheControlTestConfiguration.class })
I have an application built with JHipster which contains several tests.
I created a simple configuration class that instantiate a bean connected to an external service as such :
#Configuration
public class KurentoConfiguration {
#Bean(name = "kurentoClient")
public KurentoClient getKurentoClient(#Autowired ApplicationProperties applicationProperties) {
return KurentoClient.create(applicationProperties.getKurento().getWsUrl());
}
}
But as you would guess, this code crash during testing because the external service is not up but this code is still run during application context loading.
So I need to create a "stateless" version of this bean to be used during testing.
Here is a simple example of a test that fail because of my configuration :
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Face2FaceApp.class)
public class LogsResourceIntTest {
private MockMvc restLogsMockMvc;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
LogsResource logsResource = new LogsResource();
this.restLogsMockMvc = MockMvcBuilders
.standaloneSetup(logsResource)
.build();
}
#Test
public void getAllLogs()throws Exception {
restLogsMockMvc.perform(get("/management/logs"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
}
}
What is the solution to make this bean not highly dependent of an external service during unit testing ?
You can use the MockBean annotation in your test to replace your existing bean :
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Face2FaceApp.class)
public class LogsResourceIntTest {
#MockBean
private KurentoClient kurentoClient;
private MockMvc restLogsMockMvc;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
LogsResource logsResource = new LogsResource();
this.restLogsMockMvc = MockMvcBuilders
.standaloneSetup(logsResource)
.build();
given(kurentoClient.someCall()).willReturn("mock");
}
....
}
Here is the Spring Boot documentation :
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-mocking-beans
Thanks to the help of everyone here, I managed to solve this problem :
I created an interface of KurentoClient and implemented a proxy that call KurentoClient methods
My "normal" #Bean kurentoClient returns the implemented proxy
I writed a #TestConfiguration (UnitTestConfiguration) and added a #Bean with the same signature as the one crated above but this one returns mockito's mock(KurentoClient.class)
I created a class TestBase that every test class extends and which
contains
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyApp.class)
#ContextConfiguration(classes = UnitTestConfiguration.class)
public class TestBase {
}
I have the following spring test configuration with different profiles:
#Configuration
#ComponentScan (value = {"uk.co.test.ws" })
public class SpringTestConfig
{
#Profile( "local")
#PropertySource( "classpath:/config/local/settings.properties" )
public static class SpringTestConfigLocal
{
#Autowired
private Environment environment ;
#Bean(name= "baseUrl" )
public String setBaseUrl()
{
return environment .getRequiredProperty("baseurl.protocol" )+"://" +environment .getRequiredProperty( "baseurl.host");
}
}
and then created a base class that takes in the base url
> #RunWith (SpringJUnit4ClassRunner. class) #ContextConfiguration
> (classes = { SpringTestConfig. class }) public class BaseWsTest {
> #Autowired
> String baseUrl;
which then gets extended to other test classes like below:
public class SampleFTest extends BaseWsTest
{
#Test
public void hello() throws FileNotFoundException, Exception
{
System. out .println("base url: " + baseUrl );
When run using normal maven clean install the tests works but if I was to run it by right-clicking the method it gets a
Error creating bean with name 'uk.co.test.ws.service.base.SampleFTest': Injection of autowired dependencies failed;
You forgot to choose the profile in your SampleFTest class, you should add this line:
#ActiveProfiles(profiles = "local")
In this way the SpringTestConfigLocal will be initialized and the baseUrl bean available
EDIT: I would add a property in a .properties file so I could use a variable myprofile:
#ActiveProfiles(profiles = "${myprofile}")
And eventually, if you don't want to change the value from time to time, I would apply some logic in order to load one property file or another.
EDIT 2: I'm sorry but this doesn't work because the file is loaded after the assigment of the annotation EL value, but you can add this:
spring.profiles.active=local
to the property file and this will do the same as putting the annotation #IntegrationTest("local"). This is the code I tried:
#TestPropertySource(value="classpath:/config/test.properties")//, properties={"myaddress=cane", "myprofile=local"})
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest("${myaddress}")
//#ContextConfiguration
//#ActiveProfiles(profiles = "${myprofile}")
public class BasicJUnitTest{
protected Logger logger;
protected MockMvc mockMvc;
#Autowired
private Environment env;
#Value("${myaddress}" )
String myval;
public BasicJUnitTest(){
this.logger = LoggerFactory.getLogger(this.getClass());
}
#Test
public void test(){
logger.info("hola"+myval+ " " + env.getActiveProfiles()[0]);
}
}
I am using JUnit tests with Spring configuration defined in a class annotated with #Configuration in my JUnit Test. The tests looks like this:
#ContextConfiguration(classes = MyConfiguration.class})
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class SomeIntegrationTest {
#Autowired
private MyConfiguration myConfiguration;
#Test
public void someTest() throws Exception {
myConfiguration.myBean();
}
}
In MyConfiguration, I would like to use Spring scope SimpleThreadScope:
#Configuration
public class MyConfiguration {
#Bean
#Scope("thread")
public MyBean myBean() {
return new MyBean();
}
}
When I run the test, the scope is not registered, though. I get
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: java.lang.IllegalStateException: No Scope registered for scope 'thread'
I am aware how a custom scope can be registered programatically:
context.getBeanFactory().registerScope("thread", new SimpleThreadScope());
and I would like to avoid using XML Spring configuration.
Is there any way, how can I register the custom scope in the unit test?
Check this execution listener:
public class WebContextTestExecutionListener extends
AbstractTestExecutionListener {
#Override
public void prepareTestInstance(TestContext testContext) throws Exception {
if (testContext.getApplicationContext() instanceof GenericApplicationContext) {
GenericApplicationContext context = (GenericApplicationContext) testContext.getApplicationContext();
ConfigurableListableBeanFactory beanFactory = context
.getBeanFactory();
Scope requestScope = new SimpleThreadScope();
beanFactory.registerScope("request", requestScope);
Scope sessionScope = new SimpleThreadScope();
beanFactory.registerScope("session", sessionScope);
Scope threadScope= new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
}
}
}
in the test you can put this
#ContextConfiguration(classes = MyConfiguration.class})
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#TestExecutionListeners( { WebContextTestExecutionListener.class})
public class UserSpringIntegrationTest {
#Autowired
private UserBean userBean;
//All the test methods
}