Seperate liquibase file with test data per test class in Spring Boot - spring-boot

I want to seperate test data for particular test. For example we have two test classes A and B they are running on diffrent data so I want to create
ATestData.xml and BTestData.xml and when test class starts it should execute ATestData.xml then rollback then start test B execute BTestData.xml.
in Arquillian Persistence Extension there was #UsingDataSet("datasets/users.yml").
I started to wrtie my own annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface LiquibaseTestDataFile {
String value() default "";
}
And
#Slf4j
#Aspect
#Component
public class LiquibaseTestDataFileAspect {
#Before("execution(* (#LiquibaseTestDataFile *).*(..)) || execution(#LiquibaseTestDataFile * *(..))")
public void insertTestData(JoinPoint joinPoint){
log.info("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Class<?> declaringClass = signature.getMethod().getDeclaringClass();
LiquibaseTestDataFile myAnnotation = declaringClass.getAnnotation(LiquibaseTestDataFile.class);
//TODO if null maybe on method
//log.info(myAnnotation.value());
}
}
But it not trigers when annotation is on test class.
I am using #EnableAspectJAutoProxy in configuration
and
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {TransferManagerRestApplication.class})
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
in test class.

I have find solution by using #PostConstruct
#Component
public class LiquibaseDataTestConfiguration {
#Autowired
private SpringLiquibase springLiquibase;
public void insert(String fileName){
try {
Connection connection = springLiquibase.getDataSource().getConnection();
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
Liquibase liquibase = new liquibase.Liquibase(fileName, new ClassLoaderResourceAccessor(), database);
liquibase.update(new Contexts(springLiquibase.getContexts()), new LabelExpression(springLiquibase.getLabels()));
} catch (LiquibaseException | SQLException e) {
e.printStackTrace();
}
}
}
and in test class
#Autowired
private LiquibaseDataTestConfiguration liquibaseDataTestConfiguration;
#PostConstruct
public void initData(){
liquibaseDataTestConfiguration.insert("liquibase/AClassTest.xml");
}

Related

Verifying pointcuts being called in tests

I have a dummy project where I try figure out how to test pointcuts being triggered.
My project consists of 1 aspect bean which just prints after a foo method is called
#Component
#Aspect
public class SystemArchitecture {
#After("execution(* foo(..))")
public void after() {
System.out.println("#After");
}
}
And a FooServiceImpl with implemented foo method
#Service
public class FooServiceImpl implements FooService{
#Override
public FooDto foo(String msg) {
return new FooDto(msg);
}
}
The code works and and I can see "#After" being printed to console, but I can't check programatically if after pointcut was called using the test below.
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#Test
void shouldPass() {
fooService.foo("hello");
}
}
I've also tried using non-bean proxy as was adviced in https://stackoverflow.com/a/56312984/18224588, but this time I'm getting an obvious error cannot extend concrete aspect because my spy proxy is no longer viewed as an aspect:
public class AspectNoContextTest {
#Test
void shouldPass() {
FooService fooService = Mockito.mock(FooService.class);
SystemArchitecture systemArchitecture = Mockito.spy(new SystemArchitecture());
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(fooService);
aspectJProxyFactory.addAspect(systemArchitecture);
DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
AopProxy aopProxy = proxyFactory.createAopProxy(aspectJProxyFactory);
FooService proxy = (FooService) aopProxy.getProxy();
proxy.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}
Ok, after some digging, I found that it's possible to accomplish this by making an aspect a #SpyBean. Also AopUtils can be used for performing additional checks
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#SpyBean
private SystemArchitecture systemArchitecture;
#Test
void shouldPass() {
assertTrue(AopUtils.isAopProxy(fooService));
assertTrue(AopUtils.isCglibProxy(fooService));
fooService.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}

Cannot activate transaction for junit test

I want to test a transactional method. I added the #transactional over test method but I got an exception IllegalStateException: Failed to retrieve PlatformTransactionManager for #Transactional test. I don't know how to activate the transaction. I tried to add TestTransaction.start() in the first line of the test body but it throws an exception that the transaction is not active. I don't know what's wrong with my test.
If I remove classes in #SpringbootTest the test randomly throws NoSuchBeanException for my repositories.
My test method:
#ExtendWith(SpringExtension.class)
#DataJpaTest
#AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
class PersistenceHelperTest {
#Autowired
private ReturnRepository returnRepository;
#SpyBean
private PersistenceHelper persistenceHelper;
#Test
void removeFromDbOnWriteExceptionForNotWritableFile(#TempDir Path tempDir) {
Path testFile = tempDir.resolve("testFile.txt");
try {
String content = "This is a test";
testFile.toFile().createNewFile();
boolean writable = testFile.toFile().setWritable(false);
assertTrue("File should not be writable", writable);
persistenceHelper.saveToFileAndDB(content.getBytes(), testFile.toFile().getAbsolutePath(), returnFile, returnRepository);
fail();
} catch (Exception e) {
assertTrue("Should be instance of IOException", e instanceof IOException);
assertTrue("Should exists", Files.exists(testFile));
assertSame(0, returnRepository.findAll().size());
}
}
The class under the test:
#Component
public class PersistenceHelper {
#Transactional(rollbackFor = {IOException.class}, propagation = Propagation.REQUIRES_NEW)
public <T extends BaseEntity> void saveToFileAndDB(byte[] fileContent, String fileAbsolutePath, T entity, JpaRepository<T, Long> jpaRepository) throws IOException {
FileTransactionListener transactionListener = new FileTransactionListener(new FileDeleter(), fileAbsolutePath);
TransactionSynchronizationManager.registerSynchronization(transactionListener);
jpaRepository.save(entity);
FileUtil.writeToFile(fileAbsolutePath, fileContent);
}
}
my Springboot class:
#SpringBootApplication
#EnableTransactionManagement
#EnableJpaRepositories("packageAddress")
public class MyApplication {

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");
}
}

Spring boot repository.save() does not work in test class

I have this test class:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { CrimeServiceDBImpl.class, CrimeController.class, Crime.class })
#ComponentScan("com.springmiddleware")
#EntityScan(basePackages = {"com.springmiddleware.entities"})
#DataJpaTest
#AutoConfigureTestDatabase(replace = Replace.NONE)
#EnableJpaRepositories("com.springmiddleware")
public class TestCrimeServiceDB {
#Autowired
private CrimeServiceDBImpl service = new CrimeServiceDBImpl();
#Test
public void getAll() {
try {
List<Crime> list = this.service.getAllCrimes();
assertTrue(list.size()!=0);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The method getAllCrimes() from the service class does just this:
#Service
public class CrimeServiceDBImpl implements CrimeService{
#Autowired
private CrimeRepository repository;
private List<Crime> list = new ArrayList<Crime>();
public CrimeServiceDBImpl() {
list = UtilityMethods.readFromCSV();
};
#Override
public List<Crime> getAllCrimes() throws IOException {
repository.saveAll(list);
return this.repository.findAll();
}
If I call this method when running the application, it correctly add all my objects to the database, but when it's called from the test it doesn't add anything, but no exception is thrown.
Which database are you using? Do you mean the data is not persisted in the database after the test has finished? That's because a test always perform a rollback/cleanup when it has finished its work.

Spring & Cucumber integration: #Sql import didn't execute

I need to integrate the cucumber with spring in a practice. But I can't import some test data with spring's #Sql annotation. However the other integration tests that not use cucumber works fine. I didn't find why? The cucumber runner:
#RunWith(Cucumber.class)
#CucumberOptions(features={"classpath:features/"})
public class CucumberIT {
}
And the step defination:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes={DevDbConfig.class})
#Sql("classpath:test-reader-data.sql")
#Transactional
#ActiveProfiles("dev")
public class StepDefines {
#Autowired
ReaderService readerService;
Reader reader;
#Given("^a user with name Lily$")
public void a_user_with_name_Lily() throws Throwable {
reader = readerService.findByName("Lily"); // reader is null here!
}
#Given("^this user Lily exists$")
public void this_user_Lily_exists() throws Throwable {
assertThat(reader, notNullValue());
}
#Then("^Lily's info should be returned$")
public void lily_s_info_should_be_returned() throws Throwable {
assertThat(reader.getName(), is("Lily"));
}
}
But the following testing code can import the testing data normally:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes={DevDbConfig.class})
#Sql("classpath:test-reader-data.sql")
#Transactional
#ActiveProfiles("dev")
public class ReaderServiceTest {
#Autowired
ReaderService readerService;
#Autowired
EntityManager entityManager;
#Test
public void testQueryByIdAndShouldNotReturnNull() {
Reader reader = readerService.findByName("Lily");
assertThat(reader, notNullValue()); // reader is not null!
}
}
Thanks!
The #Sql will be executed by SqlScriptsTestExecutionListener. The Spring SpringJUnit4ClassRunner will register all of the TestExecutionListeners.
From theSqlScriptsTestExecutionListenerjava doc, it says:
Scripts and inlined statements will be executed before or after execution of the corresponding test method, depending on the configured value of the executionPhase flag.
So a class level #Sql is equivalent to all #Testmethods with individual #Sqlannotation.
However, when cucumber is running, it won't execute any #Test method and the #Sql doesn't have chance to be executed.
Finally, I have to do it myself:
#Autowired
DataSource ds;
#Given("^a user with name Lily$")
public void a_user_with_name_Lily() throws Throwable {
ScriptUtils.executeSqlScript(ds.getConnection(), new ClassPathResource("test-reader-data.sql"));
reader = readerService.findByName("Lily");
}
#Given("^this user Lily exists$")
public void this_user_Lily_exists() throws Throwable {
assertThat(reader, notNullValue());
}
#Then("^Lily's info should be returned$")
public void lily_s_info_should_be_returned() throws Throwable {
assertThat(reader.getName(), is("Lily"));
}

Resources