I have a spring boot REST API with a GET method that returns data available in a DB. I am attempting to write an integration test to test this API method. I have configured the test to use the H2 database. I am trying to add some mock data to the database before the test is executed and see if the API retrieves that data. Following is the code I have written so far.
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(locations = "classpath:application-test.properties")
public class MetaControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private ProvinceDAO provinceDAO;
@Transactional
@Before
public void addData () {
Province southern = getProvinceEntity("Southern", "දකුණ", "தென்");
provinceDAO.createEntity(southern);
System.out.println(provinceDAO.findAll(Province.class).size());
}
@Test
public void testGetProvinces() throws Exception {
MvcResult result = mvc.perform(get("/meta/provinces"))
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andReturn();
System.out.println(result.getResponse().getContentAsString());
}
}
However, when I run this code, I am getting an error saying "org.springframework.dao.InvalidDataAccessApiUsageException: No transactional EntityManager available; nested exception is java.lang.IllegalStateException: No transactional EntityManager available
"
I have also attempted using @MockBean
instead of @Autowired
to bind the provinceDAO
. Even though this prevents the error, it does not persist the entity in the database.
How should I write my testcase to test my method here?
Update:
application-test.properties
spring.datasource.url = jdbc:h2:mem:test
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
Entity -> Province.java
@Entity
@Table(name = "w4a_province")
public class Province {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private int id;
@Column(name = "province_name")
private String name;
@Column(name = "province_name_si")
private String nameSi;
@Column(name = "province_name_ta")
private String nameTa;
.
.
}
GenericDAO.java
@Repository
public class GenericDAO<T> implements IGenericDAO<T> {
@PersistenceContext
private EntityManager em;
@Override
public Session getCurrentSession() {
return this.em.unwrap(Session.class);
}
@Override
public T findByPrimaryKey(Class<T> clazz, Object primaryKey) {
return getCurrentSession().find(clazz, primaryKey);
}
@Override
public List<T> findAll(Class<T> clazz) {
DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
return criteria.getExecutableCriteria(getCurrentSession()).list();
}
@Override
public T createEntity(T entity) {
getCurrentSession().save(entity);
return entity;
}
ProvinceDAOImpl.java
@Repository
public class ProvinceDAOImpl extends GenericDAO<Province> implements ProvinceDAO {
}
MetaController.java
@RestController
@PreAuthorize("permitAll()")
public class MetaController {
private final MetaService metaService;
@Autowired
public MetaController(MetaService metService) {
this.metaService = metService;
}
@GetMapping("/meta/provinces")
public ResponseEntity<List<ProvinceDTO>> getProvinces() {
if (logger.isDebugEnabled()) {
logger.debug("Retrieving list of provinces.");
}
List<ProvinceDTO> provinces = metaService.getProvinces();
return ResponseEntity.ok(provinces);
}
}
MetaServiceImpl.java
@Service
@Transactional
public class MetaServiceImpl implements MetaService {
private final ProvinceDAO provinceDAO;
@Autowired
public MetaServiceImpl(ProvinceDAO provnceDAO) {
this.provinceDAO = provnceDAO;
}
public List<ProvinceDTO> getProvinces() {
if (logger.isDebugEnabled()) {
logger.debug("Obtaining a list of provinces from database.");
}
List<Province> entities = provinceDAO.findAll(Province.class);
if (logger.isDebugEnabled()) {
logger.debug("Converting province entities to dtos.");
}
List<ProvinceDTO> dtos = new ArrayList<>();
for (int i = 0; i < entities.size(); i++) {
Province entity = entities.get(i);
if (LocaleContextHolder.getLocale().getLanguage().equals(
GlobalConstants.LanguageIdentifiers.SINHALA_LANGUAGE_TAG)) {
dtos.add(new ProvinceDTO(entity.getId(), entity.getNameSi()));
} else if (LocaleContextHolder.getLocale().getLanguage().equals(
GlobalConstants.LanguageIdentifiers.TAMIL_LANGUAGE_TAG)) {
dtos.add(new ProvinceDTO(entity.getId(), entity.getNameTa()));
} else {
dtos.add(new ProvinceDTO(entity.getId(), entity.getName()));
}
}
return dtos;
}
}
I managed to feed the database with the required data by placing a SQL script data-h2.sql with insert queries at the test/resources folder. This prevented the requirement to use an EntityManager or a DAO.
Furthermore, I added the following property to the application-test.properties
file.
spring.datasource.platform=h2