【发布时间】:2017-06-10 14:57:36
【问题描述】:
我知道这不是什么新鲜事,但我尝试了几种方法,但都没有奏效。 我有一个简单的 Junit 测试:
@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());
}
}
此测试用例失败,因为版本号仍为 1。
我正在做的事情可能看起来有点奇怪,但这个测试只是部分的,因为我在我的 bean 内的几个属性上使用 @Audited 注释来跟踪更改。 我在这里尝试做的是检查版本号是否在更改后增加。我知道@Transactional 只是在方法结束时提交事务,所以这解释了我的方法失败的原因。
我一直在寻找的是一种在同一个测试方法中进行多次提交但同时保留从 @Before 方法到测试用例结束的事务的可见性的方法。
要遵循的最佳实践?
================================================ ================
我想我已经解决了我的问题。我不确定我的解决方案是否是最佳实践并且很好,所以我不会将其发布为回复。我认为它可能很有用,所以这是完整的课程(我的灵感来自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());
}
【问题讨论】:
-
我认为 JUnit 测试不应该提交事务。完成后执行、验证和回滚它们似乎更合适。使数据库保持与首次运行测试时相同的状态。
-
@duffymo 你说得对,但我需要在同一个对象的不同事务中模拟几个操作。我想从我上次的更新中你可以理解我想要达到的想法。
-
第一个 end transaction 和 start 很奇怪,如果有人支持你测试很难理解。还有你为什么要创建和持久化对象并为它做断言?设置部分 - 用于设置(您可以创建对象并在每个测试中使用,但县只属于设置方法,在测试方法中不可用)。在你的情况下没有断言。我看到你在 plate.setCoutry(countryRepository.findFirstByOrderByIdAsc()); 中使用它但避免在设置部分断言。你在每个方法的开头都做同样的断言。
-
方法 saveLicensePlateAndChangeCheckAudited 也做了很多检查。尝试按照princeple 一种测试方法测试事物,只是测试设计的备注
-
@sbjavateam 感谢您的建议。我在 spring-data-envers 存储库中找到了一个测试示例,再次更改了我的代码。关于检查几件事的问题:saveLicensePlateAndChangeCheckAudited这个方法是不是应该拆分成几个方法,每个assert一个?