在并行上下文中的 @WithMockUser

huangapple go评论110阅读模式
英文:

@WithMockUser in a parallel context

问题

以下是您要翻译的内容:

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

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

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. @EnableAsync
  4. @WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
  5. public class NonTest {
  6. @Test
  7. public void test() {
  8. IntStream.range(1, 10)
  9. .parallel() // 注释掉这一行,它就会正常工作
  10. .forEach(value -> {
  11. getUser(value);
  12. });
  13. }
  14. public void getUser(int value) {
  15. System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
  16. }
  17. }

当我将上述代码执行时,如果将.parallel()注释掉,它将按预期输出以下内容:

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

... 但是当我添加.parallel()时,它会抛出NullPointerException,因为某种方式下模拟的用户不存在。

当我使用ExecutorService或任何线程时,它的行为是相同的。

那么,我该如何并行执行这个方法呢?

英文:

The following code is just a simplified version of what I want to achieve.

I am using @WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"}) to mock a user in my tests.

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. @EnableAsync
  4. @WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
  5. public class NonTest {
  6. @Test
  7. public void test() {
  8. IntStream.range(1, 10)
  9. .parallel() // Comment this and it will work
  10. .forEach(value -> {
  11. getUser(value);
  12. });
  13. }
  14. public void getUser(int value) {
  15. System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
  16. }
  17. }

When I execute the above code with .parallel() commented out, it works and prints out the following as intended:

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

... but when I add the .parallel() it throws a NullPointerException since somehow the mocked user is not present.

It behaves the same way when I use an ExecutorService or any threading of some sort.

So, how do I execute the method in parallel?

答案1

得分: 3

使用.parallel()将会启动多个线程并行运行流。根据教程中的描述:

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

因此,您需要使子线程从本地线程继承SecurityContextHolder,为此,您可以使用@PostConstruct,如下所示(更多信息请参见这里):

  1. @SpringBootTest
  2. @EnableAsync
  3. @WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
  4. public class NonTest {
  5. @Test
  6. public void test() {
  7. IntStream.range(1, 10)
  8. .parallel()
  9. .forEach(this::getUser);
  10. }
  11. @PostConstruct
  12. void setGlobalSecurityContext() {
  13. SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
  14. }
  15. public void getUser(int value) {
  16. System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
  17. }
  18. }

输出

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

The use of .parallel() will spawn multiple threads to run over the stream in parallel. From the tutorial on streams:

> When a stream executes in parallel, the Java runtime partitions the
> stream into multiple substreams. Aggregate operations iterate over and
> process these substreams in parallel and then combine the results.

So you need to make the children threads inherit the SecurityContextHolder from the local thread, for this you could use @PostConstruct as follows, (see more info here):

  1. @SpringBootTest
  2. @EnableAsync
  3. @WithMockUser(username = "jane@no-domain.com", authorities = {"ROLE_ADMIN"})
  4. public class NonTest {
  5. @Test
  6. public void test() {
  7. IntStream.range(1, 10)
  8. .parallel()
  9. .forEach(this::getUser);
  10. }
  11. @PostConstruct
  12. void setGlobalSecurityContext() {
  13. SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
  14. }
  15. public void getUser(int value) {
  16. System.out.println(value + ": " + ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
  17. }
  18. }

Output

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

huangapple
  • 本文由 发表于 2020年7月25日 16:24:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/63086101.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定