@WithMockUser 在并行上下文中

Posted

技术标签:

【中文标题】@WithMockUser 在并行上下文中【英文标题】:@WithMockUser in a parallel context 【发布时间】:2020-11-15 01:25:23 【问题描述】:

以下代码只是我想要实现的简化版本。

我正在使用@WithMockUser(username = "jane@no-domain.com", authorities = "ROLE_ADMIN") 在我的测试中模拟用户。

@RunWith(SpringRunner.class)
@SpringBootTest
@EnableAsync
@WithMockUser(username = "jane@no-domain.com", authorities = "ROLE_ADMIN")
public class NonTest 

    @Test
    public void test() 
        IntStream.range(1, 10)
            .parallel() // Comment this and it will work
            .forEach(value -> 
                getUser(value);
            );
    

    public void getUser(int value) 
        System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
    


当我在注释掉.parallel() 的情况下执行上述代码时,它可以正常工作并按预期打印出以下内容:

1: jane@no-domain.com
2: jane@no-domain.com
3: jane@no-domain.com
4: jane@no-domain.com
5: jane@no-domain.com
6: jane@no-domain.com
7: jane@no-domain.com
8: jane@no-domain.com
9: jane@no-domain.com

...但是当我添加.parallel() 时,它会抛出NullPointerException,因为不知何故被模拟的用户不存在。

当我使用 ExecutorService 或任何类型的线程时,它的行为方式相同。

那么,如何并行执行该方法?

【问题讨论】:

【参考方案1】:

.parallel() 的使用将产生多个线程以并行运行流。来自tutorial 直播:

当流并行执行时,Java 运行时将 流成多个子流。聚合操作迭代和 并行处理这些子流,然后合并结果。

所以你需要让子线程从本地线程继承SecurityContextHolder,为此你可以使用@PostConstruct,如下所示(查看更多信息here):

@SpringBootTest
@EnableAsync
@WithMockUser(username = "jane@no-domain.com", authorities = "ROLE_ADMIN")
public class NonTest 

    @Test
    public void test() 
        IntStream.range(1, 10)
            .parallel()
            .forEach(this::getUser);
    

    @PostConstruct
    void setGlobalSecurityContext() 
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    

    public void getUser(int value) 
        System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
    


输出

6: jane@no-domain.com
7: jane@no-domain.com
1: jane@no-domain.com
2: jane@no-domain.com
3: jane@no-domain.com
9: jane@no-domain.com
4: jane@no-domain.com
8: jane@no-domain.com
5: jane@no-domain.com

【讨论】:

谢谢。那行得通。我也学到了一些东西。我不知道子线程应该从本地线程继承SecurityContext

以上是关于@WithMockUser 在并行上下文中的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot + webflux:并行运行某些步骤时上下文丢失

编程中什么叫上下文

多核并行编程技术

使用 async/await 并行执行任务继续

@WithMockUser 在集成测试中不起作用 - Spring boot

@WithMockUser 忽略用户名、密码字段?