代码之家  ›  专栏  ›  技术社区  ›  fg78nc

在reactor.core.publisher.monoawhen$whencoordator上的spring webflux中的filepart mock上的npe

  •  0
  • fg78nc  · 技术社区  · 8 年前

    对于我遇到的以下问题,我希望你能给我一些提示。在中测试多部分文件上载服务方法时 Spring Reactive WebFlux 应用程序,我正在为 reactor.core.publisher.MonoWhen$WhenCoordinator 如下

    java.lang.NullPointerException
        at reactor.core.publisher.MonoWhen$WhenCoordinator.subscribe(MonoWhen.java:149) 
    

    完整的日志也列在下面。

    测试:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class FileServiceTest2 {
    
    
    @MockBean
    private UploadedImageRepository uploadedImageRepository;
    
    ...
    
           @Test
            public void assembleImageTest() {
                UploadedImage ui1 = new UploadedImage("1", "ui1.png");
                UploadedImage ui2 = new UploadedImage("2", "ui2.png");
    
                FilePart filePart1 = mock(FilePart.class);
                FilePart filePart2 = mock(FilePart.class);
    
                given(this.uploadedImageRepository.save(ui1))
                        .willReturn(Mono.just(ui1));
                given(this.uploadedImageRepository.save(ui2))
                        .willReturn(Mono.just(ui2));
                given(this.uploadedImageRepository.findAll())
                        .willReturn(Flux.just(ui1, ui2));
    
                given(filePart1.filename())
                        .willReturn(ui1.getImageName());
                given(filePart1.transferTo(any()))
                        .willReturn(Mono.empty());
                given(filePart2.filename())
                        .willReturn(ui2.getImageName());
                given(filePart2.transferTo(any()))
                        .willReturn(Mono.empty());
    
                Flux<FilePart> files = Flux.just(filePart1, filePart2);
    
                StepVerifier.create(this.uploadService.createFile(files))
                        .verifyComplete();
            }
    

    在测试中:

    @Service
    public class UploadService {
    
    Mono<Void> createFile(Flux<FilePart> fileParts) {
            return fileParts.flatMap(part -> {
                Mono<UploadedImage> savedToDBImage = this.uploadedImageRepository.save(
                        new UploadedImage(UUID.randomUUID().toString(), part.filename()))
                        .log("createFile-fileSavedToDB"); // NPE!
    
                Mono<Void> copiedFile = Mono.just(Paths.get(UPLOAD_URL, part.filename()).toFile())
                        .log("createFile-pathAssembled")
                        .doOnNext(destinationFile -> {
                            try {
                                destinationFile.createNewFile();
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        })
                        .log("createFile-fileAssembled")
                        .flatMap(part::transferTo)
                        .log("createFile-fileCopied");
    
                return Mono.when(savedToDBImage, copiedFile)
                        .log("createFile-monoWhen");
            })
                    .log("createFile-flatMap")
                    .then()
                    .log("createFile-done");
        }
    

    UploadedImage 等级(W Lombok):

    @Data
    @RequiredArgsConstructor
    @NoArgsConstructor
    public class UploadedImage {
    
            @NonNull private String id;
            @NonNull private String imageName;
    
    }
    

    SpringData反应式存储库:

    @Repository
    public interface UploadedImageRepository extends ReactiveCrudRepository<UploadedImage, String> {
    
    }
    

    日志如下:

    java.lang.NullPointerException
        at reactor.core.publisher.MonoWhen$WhenCoordinator.subscribe(MonoWhen.java:149)
        at reactor.core.publisher.MonoWhen.subscribe(MonoWhen.java:99)
        at reactor.core.publisher.MonoOnAssembly.subscribe(MonoOnAssembly.java:76)
        at reactor.core.publisher.MonoLogFuseable.subscribe(MonoLogFuseable.java:53)
        at reactor.core.publisher.Mono.subscribe(Mono.java:3080)
        at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:372)
        at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:198)
        at reactor.core.publisher.FluxArray$ArraySubscription.slowPath(FluxArray.java:118)
        at reactor.core.publisher.FluxArray$ArraySubscription.request(FluxArray.java:91)
        at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:138)
        at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:332)
        at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:172)
        at reactor.core.publisher.FluxArray.subscribe(FluxArray.java:53)
        at reactor.core.publisher.FluxArray.subscribe(FluxArray.java:59)
        at reactor.core.publisher.FluxLogFuseable.subscribe(FluxLogFuseable.java:53)
        at reactor.core.publisher.FluxFlatMap.subscribe(FluxFlatMap.java:97)
        at reactor.core.publisher.FluxLog.subscribe(FluxLog.java:50)
        at reactor.core.publisher.MonoIgnoreElements.subscribe(MonoIgnoreElements.java:37)
        at reactor.core.publisher.MonoLog.subscribe(MonoLog.java:51)
        at reactor.core.publisher.Mono.subscribe(Mono.java:3080)
        at reactor.test.DefaultStepVerifierBuilder$DefaultStepVerifier.verify(DefaultStepVerifierBuilder.java:728)
        at reactor.test.DefaultStepVerifierBuilder$DefaultStepVerifier.verify(DefaultStepVerifierBuilder.java:700)
        at reactor.test.DefaultStepVerifierBuilder.verifyComplete(DefaultStepVerifierBuilder.java:566)
        at pb.sl.UploadService.createFile(FileServiceTest2.java:112)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
        at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
        at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
        at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    
    1 回复  |  直到 8 年前
        1
  •  2
  •   Brian Clozel    8 年前

    仔细看,我认为您没有像预期的那样模拟存储库,在测试中,存储库调用返回null。

    您没有使用mockito参数匹配器,而是使用参数的具体实例。稍后在服务实现中,将调用此方法,但使用不同的实例。我猜莫基托在用 equals 检查给定的是否与模拟调用匹配-可能是 UploadedImage 在这方面可以改进吗?

    given(this.uploadedImageRepository.save(ui1)) 应该是:

    given(this.uploadedImageRepository.save(any()))
    .willAnswer(invocation -> Mono.just(invocation.getArgument(0)))