首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在jupiter @BeforeAll方法中获取LazyInitializationException

在jupiter @BeforeAll方法中获取LazyInitializationException
EN

Stack Overflow用户
提问于 2021-09-16 13:50:28
回答 1查看 60关注 0票数 1

在我的集成测试中,我想提前用@BeforeAll (见下文)在我的测试用例中可以依赖的数据填充我的系统。

代码语言:javascript
复制
package com.ksteindl.chemstore.service;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import javax.transaction.Transactional;
//some other import of my own stuff

@ExtendWith(SpringExtension.class)
@ActiveProfiles("test")
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class ShelfLifeServiceTest extends BaseControllerTest {

    @Autowired
    private ShelfLifeService shelfLifeService;
    @Autowired
    private ChemTypeService chemTypeService;

    @BeforeAll
    static void setUpTestDb(@Autowired ShelfLifeService shelfLifeService,@Autowired ChemTypeService chemTypeService) {
        ShelfLifeInput input = LabAdminTestUtils.getSolidForAlphaInput();
        Long chemTypeId = chemTypeService.getChemTypes().stream()
                .filter(chemType -> chemType.getName().equals(LabAdminTestUtils.SOLID_COMPOUND_NAME))
                .findAny()
                .get()
                .getId();
        input.setChemTypeId(chemTypeId);
        shelfLifeService.createShelfLife(input, AccountManagerTestUtils.BETA_LAB_MANAGER_PRINCIPAL);
    }

    @Test
    @Rollback
    @Transactional
    public void testCreateShelfLife_whenAllValid_gotNoException() {
        ShelfLifeInput input = LabAdminTestUtils.getSolidForBetaInput();
        Long chemTypeId = chemTypeService.getChemTypes().stream()
                .filter(chemType -> chemType.getName().equals(LabAdminTestUtils.SOLID_COMPOUND_NAME))
                .findAny()
                .get()
                .getId();
        input.setChemTypeId(chemTypeId);
        shelfLifeService.createShelfLife(input, AccountManagerTestUtils.BETA_LAB_MANAGER_PRINCIPAL);
    }
}

我的问题是当我运行测试时,我从@BeforeAll方法抛出了一个LazyInicializtionException

代码语言:javascript
复制
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.ksteindl.chemstore.domain.entities.Lab.labManagers, could not initialize proxy - no Session
...
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:528)
at com.ksteindl.chemstore.service.ShelfLifeService.getAndValidateLab(ShelfLifeService.java:92)
at com.ksteindl.chemstore.service.ShelfLifeService.createOrUpdateShelfLife(ShelfLifeService.java:65)
at com.ksteindl.chemstore.service.ShelfLifeService.createShelfLife(ShelfLifeService.java:47)
at com.ksteindl.chemstore.service.ShelfLifeServiceTest.setUpTestDb(ShelfLifeServiceTest.java:39)

有趣的是,当我注释掉@BeforeAll方法时,我的测试运行正常,没有任何异常。正如您所看到的,这两个方法的内容几乎相同(只是输入不同,以防止彼此冲突)。抛出异常的确切代码如下所示:

代码语言:javascript
复制
private Lab getAndValidateLab(String labKey, Principal principal) {
        Lab lab = labService.findLabByKey(labKey);
        lab.getLabManagers().stream().filter(/*some predicate*/).findAny().orElseThrow(/*throw validation Exception*/);
        return lab;
    }

这是真的,Lab和labManagers属性之间的关系是惰性的,但是我不能理解为什么Spring不像在testCreateShelfLife_whenAllValid_gotNoException中那样在一个事务中获得这些数据。当然,ShelfLifeService.createShelfLife()在Rest控制器调用中工作得非常好。谢谢你的帮助!实体:

代码语言:javascript
复制
@Entity
@Data
public class Lab {
    //...
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "MANAGER_OF_LAB_TABLE", joinColumns = @JoinColumn(name = "LAB_ID"), inverseJoinColumns = @JoinColumn(name = "APP_USER_ID"))
    @JsonIgnore
    private List<AppUser> labManagers;
}

@Entity
@Data
public class AppUser {
//...
    @ManyToMany(mappedBy = "labManagers")
    private List<Lab> managedLabs;
}
EN

回答 1

Stack Overflow用户

发布于 2021-09-16 14:19:27

@BeforeAll (在初始化Spring容器之前运行)更改为@BeforeEach (将在每次测试之前运行,在Spring容器初始化之后运行),但在构建测试和Spring容器之后运行。

我认为在Spring容器完全构建之前,chemTypeService已经在@BeforeAll中执行了。-有点猜测

在每次测试之前,也可以查看@DirtiesContext来重新构建Spring上下文。

查看此tutorial

另一个有点老套的解决方案是在spring容器初始化后创建自己的类来加载测试数据:

代码语言:javascript
复制
@Service
@Profile("test")
public class TestInit {

    @Autowired
    private ShelfLifeService shelfLifeService;
    @Autowired
    private ChemTypeService chemTypeService;

    @PostConstruct
    private void init() {
        ShelfLifeInput input = LabAdminTestUtils.getSolidForAlphaInput();
        Long chemTypeId = chemTypeService.getChemTypes().stream()
                .filter(chemType -> chemType.getName().equals(LabAdminTestUtils.SOLID_COMPOUND_NAME))
                .findAny()
                .get()
                .getId();
        input.setChemTypeId(chemTypeId);
        shelfLifeService.createShelfLife(input, AccountManagerTestUtils.BETA_LAB_MANAGER_PRINCIPAL);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69209673

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档