Reputation: 6244
I know it's not something new but I tried several approachs found and they didn't work. I've a simple Junit test:
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class LicensePlateTests {
@Autowired
private LicensePlateRepository licensePlateRepository;
@Autowired
private CountryRepository countryRepository;
@Before
public void setup() {
TestTransaction.start();
Country country = new Country();
country.setName("Italy");
country.setIsoCode("IT");
countryRepository.save(country);
assertEquals(1, countryRepository.count());
}
@Test
public void saveLicensePlateAndChangeCheckAudited() {
assertEquals(1, countryRepository.count());
LicensePlate plate = new LicensePlate();
plate.setLicensePlate("AA123BB");
plate.setEngineEuroLevel(3);
plate.setCoutry(countryRepository.findFirstByOrderByIdAsc());
plate = licensePlateRepository.save(plate);
assertEquals(1, licensePlateRepository.count());
plate.setEngineEuroLevel(5);
plate = licensePlateRepository.save(plate);
//always 1 plate
assertEquals(1, licensePlateRepository.count());
//different version number
assertEquals(2, plate.getVersion().intValue());
}
}
This test case fails because the version number remains 1.
What I'm doing could seem a bit strange but this test is just partial and is done because I'm using @Audited annotation on several properties inside my bean to track changes. What I was trying to do here is checking if the version number is incremented after a change. I know that @Transactional commit the transaction just at the end of the method and so this explains why my method fails.
What I was looking for is a way to make several commits in the same test method but at the same time preserving the visibilily of the transaction from the @Before method to the end of the test case.
Some best practice to follow?
===============================================================
I think I've solved my problem. I'm not sure my solution is a best practice and it's good, so I don't post it as reply. I think it could be useful so this is the complete class (I took inspiration from https://github.com/spring-projects/spring-data-envers/blob/master/src/test/java/org/springframework/data/envers/repository/support/RepositoryIntegrationTests.java)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:test.properties")
public class LicensePlateAuditableTests {
private Logger log = LogManager.getLogger();
@Autowired
private LicensePlateRepository licensePlateRepository;
@Autowired
private CountryRepository countryRepository;
@Before
public void setup() {
licensePlateRepository.deleteAll();
countryRepository.deleteAll();
Country country = new Country();
country.setName("Italy");
country.setIsoCode("IT");
countryRepository.save(country);
}
@Test
public void saveLicensePlateAndChangeCheckAudited() {
assertEquals(1, countryRepository.count());
LicensePlate plate = new LicensePlate();
plate.setLicensePlate("AA123BB");
plate.setEngineEuroLevel(3);
plate.setCoutry(countryRepository.findFirstByOrderByIdAsc());
plate = licensePlateRepository.save(plate);
// First version number is 1
assertEquals(1, plate.getVersion());
// Changing some auditable data
plate.setEngineEuroLevel(5);
plate.setLicensePlate("AA956BB");
plate = licensePlateRepository.save(plate);
// different version number
assertEquals(2, plate.getVersion());
// I should have 2 revisions
assertEquals(2, licensePlateRepository.findRevisions(plate.getId()).getContent().size());
Revisions<Integer, LicensePlate> revisions = licensePlateRepository.findRevisions(plate.getId());
int i = 1;
for (Revision<Integer, LicensePlate> rev : revisions.getContent()) {
if (i == 1) {
// At the beginning the engine level was 3
assertEquals(3, rev.getEntity().getEngineEuroLevel());
// At the beginning the place number was AA123BB
assertEquals("AA123BB", rev.getEntity().getLicensePlate());
}
if (i == 2) {
// Then the engine level became 5
assertEquals(5, rev.getEntity().getEngineEuroLevel());
// Then the license plate number became AA956BB
assertEquals("AA956BB", rev.getEntity().getLicensePlate());
}
i++;
}
// Check if the entry in the database has updated data
assertEquals(5, licensePlateRepository.findOne(plate.getId()).getEngineEuroLevel());
assertEquals("AA956BB", licensePlateRepository.findOne(plate.getId()).getLicensePlate());
}
Upvotes: 0
Views: 1713
Reputation: 5407
your comments in test method give you hints how many tests method should be. Just advice : you should follow on one name convention for tests method that is appropriate for you and your team. In my projects I get used to start test method's name with 'check' , 'verify'... and explaine use case that I check in method. something like this (just idea as you didn't show real classes) also I tried to show how test's method name might looks like :
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:test.properties")
public class LicensePlateAuditableTests {
private Logger log = LogManager.getLogger();
@Autowired
private LicensePlateRepository licensePlateRepository;
@Autowired
private CountryRepository countryRepository;
private LicensePlate plate;
private final String PLATE_NUMBER_FIRST = "AA123BB";
private final String PLATE_NUMBER_SECOND = "AA956BB";
private int ENGINE_EURO_LEVEL_FIRST = 3;
private int ENGINE_EURO_LEVEL_SECOND = 3;
@Before
public void setup() {
licensePlateRepository.deleteAll();
countryRepository.deleteAll();
Country country = new Country();
country.setName("Italy");
country.setIsoCode("IT");
countryRepository.save(country);
}
@Test
public void checkThatVersionIsOneAfterCreateLicensePlate() {
//given
plate = createLicensePlateWithDefaultCountry(PLATE_NUMBER_FIRST, ENGINE_EURO_LEVEL_FIRST);
//when
plate = licensePlateRepository.save(plate);
//then
// First version number is -- comment : if you want to comment something , include it into assert fail message
assertEquals("version should be 1 for just created LicensePlate ", 1, plate.getVersion());
}
@Test
public void check_that_version_is_increased_when_changing_some_auditable_data() {
//given
plate = createLicensePlateWithDefaultCountry(PLATE_NUMBER_FIRST, ENGINE_EURO_LEVEL_FIRST);
plate = licensePlateRepository.save(plate);
//when
setPlateEngineEuroLevelAndLicensePlate(PLATE_NUMBER_SECOND,ENGINE_EURO_LEVEL_SECOND);
plate = licensePlateRepository.save(plate);
//then
assertEquals("version should be increased when Changing some auditable data",2, plate.getVersion());
// Check if the entry in the database has updated data
LicensePlate plateInDB = licensePlateRepository.findOne(plate.getId());
assertNotNull(".. explanation..." , plateInDB);
assertPlateNumberAndEngineEuroLevelAsInPlate(PLATE_NUMBER_SECOND , ENGINE_EURO_LEVEL_SECOND, plateInDB);
}
@Test
public void verify_revisions_after_two_changes() {
//given
plate = createLicensePlateWithDefaultCountry(PLATE_NUMBER_FIRST, ENGINE_EURO_LEVEL_FIRST);
plate = licensePlateRepository.save(plate);
//when
setPlateEngineEuroLevelAndLicensePlate(PLATE_NUMBER_SECOND,ENGINE_EURO_LEVEL_SECOND);
plate = licensePlateRepository.save(plate);
//then
Revisions<Integer, LicensePlate> revisions = licensePlateRepository.findRevisions(plate.getId());
assertNotNull(".....something like : revisions should be found...." ,revisions);
assertNotNull(".....something like : revisions.getContent should be found...." ,revisions.getContent());
assertFalse(" should be present content for revisions " , revisions.getContent().isEmpty());
assertEquals("I should have 2 revisions" ,2, revisions.getContent().size());
//!!!! if you sure about order !!!!
Revision<Integer, LicensePlate> revFirst = revisions.getContent().get(0);
Revision<Integer, LicensePlate> revSecond = revisions.getContent().get(1);
assertPlateNumberAndEngineEuroLevelAsInPlate(PLATE_NUMBER_FIRST, ENGINE_EURO_LEVEL_FIRST, revFirst.getEntity());
assertPlateNumberAndEngineEuroLevelAsInPlate(PLATE_NUMBER_SECOND , ENGINE_EURO_LEVEL_SECOND, revSecond.getEntity());
}
private void assertPlateNumberAndEngineEuroLevelAsInPlate(String plateNumber , int engineEuroLevel , LicensePlate plate){
assertEquals(engineEuroLevel, plate.getEngineEuroLevel());
assertEquals(plateNumber , plate .getLicensePlate());
}
private LicensePlate createLicensePlateWithDefaultCountry(String plateNumber , int engineEuroLevel){
LicensePlate plate = new LicensePlate();
setPlateEngineEuroLevelAndLicensePlate(plateNumber , engineEuroLevel);
plate.setCoutry(countryRepository.findFirstByOrderByIdAsc());
return plate;
}
private void setPlateEngineEuroLevelAndLicensePlate(String plateNumber , int engineEuroLevel){
plate.setEngineEuroLevel(engineEuroLevel);
plate.setLicensePlate(plateNumber);
}
}
Upvotes: 1