Spring JUnit 5 ExtendWith TestContainer - spring-boot

I'm trying to reutilize a container and I'm trying to use JUnit5 ExtendWith feature but I'm still getting:
Connection to localhost:5432 refused.
If I have the same logic inside each test everything works as expected.
#Testcontainers
#SpringBootTest
#ExtendWith({PostgresTestContainersExtension.class})
public class ApplicationJUnit5Test {
#Autowired
private HeroClassicJDBCRepository repositoryUnderTest;
#Test
public void test1() {
System.out.println("junit version: " + Version.id());
Collection<Hero> heroes = repositoryUnderTest.allHeros();
assertThat(heroes).hasSize(1);
repositoryUnderTest.addHero(new Hero("bb", "bb"));
Collection<Hero> heroesAfter = repositoryUnderTest.allHeros();
assertThat(heroesAfter).hasSize(2);
}
}
Extention:
public class PostgresTestContainersExtension implements BeforeAllCallback,
BeforeTestExecutionCallback {
private static final String IMAGE_NAME = "registry.mycomp.com/db/mariadb:10.4.11";
#DynamicPropertySource
static void properties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", container::getJdbcUrl);
registry.add("spring.datasource.password", container::getPassword);
registry.add("spring.datasource.username", container::getUsername);
}
#Container
public static PostgreSQLContainer container = new PostgreSQLContainer()
.withUsername("duke")
.withPassword("password")
.withDatabaseName("test");
#Override
public void beforeAll(ExtensionContext extensionContext) {
startContainerIfNeed();
}
#Override
public void beforeTestExecution(ExtensionContext extensionContext) {
startContainerIfNeed();
}
public void startContainerIfNeed() {
if (!container.isRunning()) {
container.start();
}
}
}

As far as I know #DynamicPropertySource can only be used in the test class itself or a superclass. You’ll have to move the properties method over.

Related

Force Spring Boot to override default configurations

I'm trying to implement the usage of Testcontainers as an alternative for IT test on a project, currently the project it's using H2 as datasource for testing, the matter is that no matter what I try I'm not able to override those configurations in order to create a custom datasource by using a DB container, what I've tried so far:
Setting the datasource attributes directly on the application-testcontainers.yml file + #ActiveProfiles("testcontainers") annotation.
spring:
datasource:
url: jdbc:postgresql://localhost:5432/testcontainers
username: user
password: 123456
#RunWith(MockitoJUnitRunner.class)
#ActiveProfiles("testcontainers")
public final class MyTestClass {
}
Creating an extension class in order to set the datasource attributes (overriding the beforeAll method):
public class TestcontainersExtension implements BeforeAllCallback, AfterAllCallback {
private PostgreSQLContainer<?> container;
#Override
public void beforeAll(ExtensionContext context) throws Exception {
container = new PostgreSQLContainer<>("postgres:9.4")
.withDatabaseName("testcontainers")
.withUsername("user")
.withPassword("123456")
.withExposedPorts(5432);
container.start();
System.setProperty("spring.datasource.url", container.getJdbcUrl());
System.setProperty("spring.datasource.username", container.getUsername());
System.setProperty("spring.datasource.password", container.getPassword());
}
#Override
public void afterAll(ExtensionContext context) throws Exception {
}
}
#RunWith(MockitoJUnitRunner.class)
#ExtendWith(TestcontainersExtension.class)
public final class MyTestClass {
}
Using #DynamicPropertySource method in order to set the configuration properties dynamically
#RunWith(MockitoJUnitRunner.class)
MyTestClass {
#Container
static PostgreSQLContainer<?> container =
new PostgreSQLContainer<>("postgres:9.4")
.withDatabaseName("testcontainers")
.withUsername("user")
.withPassword("123456")
.withExposedPorts(5432);
#DynamicPropertySource
static void setTestProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", () -> container.getJdbcUrl());
registry.add("spring.datasource.username", () -> container.getUsername());
registry.add("spring.datasource.password", () -> container.getPassword());
}
}
#ContextConfiguration + an initializer class, also trying to set the properties dynamically
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(initializers = {MyTestClass.Initializer.class})
public final class MyTestClass {
#Container
static PostgreSQLContainer<?> container =
new PostgreSQLContainer<>("postgres:9.4")
.withDatabaseName("testcontainers")
.withUsername("user")
.withPassword("123456")
.withExposedPorts(5432);
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
TestPropertyValues.of(
"spring.datasource.url=" + container.getJdbcUrl(),
"spring.datasource.username=" + container.getUsername(),
"spring.datasource.password=" + container.getPassword()
).applyTo(applicationContext.getEnvironment());
}
}
}
None of the above worked for me, I’ll appreciate any hint or alternative.

How to use Spring boot AutoWired and ScheduledExecutorService?

I need to use autowired in more than one class with ScheduledExecutorService, what I have tried is shown in this code. logging size of User list in below example always shows 0, even after user added to arraylist. How to properly use Autowired and ScheduledExecutorService in spring boot?
#Component
public class AnotherClass {
List<User> users = new ArrayList();
public void addUser(User user){
users.add(user);
}
public void logUsers(){
logger.info("User size " + users.size()); <================= Always logs 0, when called from executor
}
}
#RestController
public class SecondClass {
#Autowired
private AnotherClass anotherClass;
#GetMapping(value="/user/test")
public void logUsers(){
anotherClass.addUser(new User());
}
}
Application Class
#Component
#SpringBootApplication
public class SpringBootDemoApplication {
private ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
#Autowired
private AnotherClass anotherClass;
#PostConstruct
public void init() {
logger();
}
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
public void logger(){
exec.scheduleAtFixedRate(new Runnable(){
#Override
public void run(){
try {
anotherClass.logUsers();
}catch (Exception e){
}
}
}, 2000, 1000, TimeUnit.MILLISECONDS);
}
}
The code works if you use the Spring #Autowired and not the #AutoWired Annotation.

Spring Boot + DynamoDBTypeConverter dependancy injection

I'm trying to get DI working with a sample DynamoDBTypeConverter I'm playing around with and having no luck at all :( My service is always null and throws an error as a result in my jUnit test.
Here's my converter:
#Component
public class ArmTypeConverter implements DynamoDBTypeConverter<String, Arm> {
#Autowired
private ArmRepository armRepository;
#Override
public String convert(Arm Arm) {
return arm.getId();
}
#Override
public Arm unconvert(String id) {
return armRepository.findOne(id);
}
}
My application main:
#SpringBootApplication
#ComponentScan
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving=EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
#EnableAutoConfiguration
public class ArmApplication implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(ArmApplication.class, args);
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
}
My service:
#Service
public class ArmServiceImpl implements ArmService {
#Autowired
private ArmRepository armRepository;
#Override
public Arm create(String length, Set<Register> registers) {
Date now = new Date();
Arm arm = new Arm();
arm.setLength("85cm");
return armRepository.save(arm);
}
}
My Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class ArmServiceTests {
#Autowired
private ArmService armService;
#Autowired
private TorsoService torsoService;
private Arm arm;
#Before
public void before() {
arm = armService.create("85cm", null);
torsoService.create("150cm", arm);
}
#After
public void after() {
// do nothing for now...
}
#Test
#WithUserDetails("admin#somewhere.com")
public void getArmTest() {
Arm c = armService.getArm(arm.getId());
assertThat(c).isNotNull();
assertThat(c.getId()).isEqualTo(arm.getId());
}
}
What am I doing wrong?
The issue was that I didn't have load time weaving configured properly

Spring integration test with PowerMockito + TestNG leads to InvocationTargetException

I'm trying to mock a static method with PowerMockito in an integration test with TestNG, but no joy so far.
#PrepareForTest({ HttpCommonClientUtils.class })
public class LiveChannelServiceTestNg extends LiveBaseTestNg {
#Autowired
private LiveChannelShareService liveChannelService;
#Resource(name = "liveSettingService")
private LiveSettingShareService liveSettingService;
#Autowired
private VCloudHelper vcloudHelper;
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
static String result = "{\\\"cid\\\":\\\"0aba025de6604ccb931bd9868bddba9a\\\",\\\"duration\\\":120,\\\"format\\\":0,\\\"gmtCreate\\\":1486378732486,\\\"hlsPullUrl\\\":\\\"http://pullhls03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a/playlist.m3u8\\\",\\\"httpPullUrl\\\":\\\"http://flv03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a.flv?netease=flv03f9fed7.live.126.net\\\",\\\"id\\\":1,\\\"name\\\":\\\"直播频道1\\\",\\\"needRecord\\\":1,\\\"pushUrl\\\":\\\"rtmp://p03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a?wsSecret=e5cf3b5c060271fd23ba56469a803a99&wsTime=1486378731\\\",\\\"referType\\\":0,\\\"rtmpPullUrl\\\":\\\"rtmp://v03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a\\\",\\\"status\\\":0,\\\"type\\\":0}";
static String cid = "0aba025de6604ccb931bd9868bddba9a";
#BeforeClass
public void setUp() throws Exception {
/* 公用的环境初始化... */
}
#BeforeMethod
public void testSetUp() throws Exception {
}
#Test
public void test_static() {
String result = "{\"cid\":\"0aba025de6604ccb931bd9868bddba9a\",\"duration\":120,\"format\":0,\"gmtCreate\":1486378732486,\"hlsPullUrl\":\"http://pullhls03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a/playlist.m3u8\",\"httpPullUrl\":\"http://flv03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a.flv?netease=flv03f9fed7.live.126.net\",\"id\":1,\"name\":\"直播频道1\",\"needRecord\":1,\"pushUrl\":\"rtmp://p03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a?wsSecret=e5cf3b5c060271fd23ba56469a803a99&wsTime=1486378731\",\"referType\":0,\"rtmpPullUrl\":\"rtmp://v03f9fed7.live.126.net/live/0aba025de6604ccb931bd9868bddba9a\",\"status\":0,\"type\":0}";
PowerMockito.mockStatic(HttpCommonClientUtils.class);
PowerMockito.when(HttpCommonClientUtils.getHtmlByPostMethod(Matchers.any(HttpClient.class),
Matchers.any(HttpDataProvider.class))).thenReturn(result);
LiveChannelDto dto = liveChannelService.getOrGenerateChannleByBindInfo(0, 1, 101L);
Assert.assertEquals(cid, dto.getCid());
}
When I run this test, a InvocationTargetException is appear

Spring boot check external service status on boot

I want check some external http service before my Spring Boot is ready.
The url to the external web service are stored in a property file with a #ConfigurationProperties class.
How do this check i tried using a springApplication.addListner() with a ping method. But the property class have not then been initialized.
public class ApplicationStartListener implements ApplicationListener<ApplicationPreparedEvent> {
#Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
String url = AppProp.getURL();
inet = InetAddress.getByName(url );
inet.isReachable(5000)
...
application.yml
tops:
http://service.com
#Component
#ConfigurationProperties("tops")
public class AppProp{
private static String url;
public static String getUrl() {
The easiest way to accomplish this is to implement the ApplicationRunner interface.
From the Spring Boot documentation [1]
If you need to run some specific code once the SpringApplication has started, you can implement the ApplicationRunner or CommandLineRunner interfaces. Both interfaces work in the same way and offer a single run method which will be called just before SpringApplication.run(…​) completes.
[1] https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-command-line-runner
Assuming you have url defined in application.properties:
#SpringBootApplication
public class MyApplication implements ApplicationRunner
{
#Inject
private AppConfig appConfig;
#Inject
private ConfigurableApplicationContext applicationContext;
public static void main(String[] args)
{
SpringApplication.run(MyApplication.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception
{
InetAddress inetAddress = InetAddress.getByName(appConfig.getUrl());
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Component
#ConfigurationProperties
public static class AppConfig
{
private String url;
public String getUrl()
{
return url;
}
public void setUrl(String url)
{
this.url = url;
}
}
}
If you need even more control than this, you can use SpringApplicationRunListener [2]
[2] http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/SpringApplicationRunListener.html
#SpringBootApplication
public class MyApplication implements SpringApplicationRunListener
{
public MyApplication() { }
public MyApplication(SpringApplication springApplication, String[] args) { }
public static void main(String[] args)
{
SpringApplication.run(MyApplication.class, args);
}
#Override
public void started() { }
#Override
public void environmentPrepared(ConfigurableEnvironment environment)
{
// 1st opportunity
InetAddress inetAddress = InetAddress.getByName(environment.getProperty("url"));
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Override
public void contextPrepared(ConfigurableApplicationContext context)
{
// 2nd opportunity
InetAddress inetAddress = InetAddress.getByName(context.getEnvironment().getProperty("url"));
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Override
public void contextLoaded(ConfigurableApplicationContext context)
{
// 3rd opportunity
InetAddress inetAddress = InetAddress.getByName(context.getEnvironment().getProperty("url"));
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Override
public void finished(ConfigurableApplicationContext context, Throwable exception)
{
// 4th opportunity
InetAddress inetAddress = InetAddress.getByName(context.getEnvironment().getProperty("url"));
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Component
#ConfigurationProperties
public static class AppConfig {
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
}
then create META-INF\spring.factories and add
org.springframework.boot.SpringApplicationRunListener=com.foobar.MyApplication

Resources