Junit: как покрыть CompletableFuture Code - PullRequest
0 голосов
/ 16 мая 2019

Я новичок в Junit и недавно столкнулся с этой проблемой.Я не могу писать тестовые примеры кода везде, где я использовал CompletableFuture в моем коде.Как показано ниже Java-файл

Обновлено

AuditService.java

@Autowired
Executor existingThreadPool;

@Override
public void auditData(List<ErrorDetails> alertList) {
    CompletableFuture.runAsync(() -> {
        if (alertList.isEmpty())
            //privateMethodCall1
        else
           //privateMethodCall2
    }, existingThreadPool);
}

Я перешел по этой ссылке и попробовал решение ниже, все еще получая NPE для CompletableFuture Как ошибка ниже.

AuditServiceTest.java

@InjectMock
AuditService auditService;

@Mock
private CompletableFuture<Void> completableFuture = null;

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
    completableFuture = CompletableFuture.runAsync(new Runnable() {
        @Override
        public void run() {}
    },Executors.newSingleThreadExecutor());
}

@Test
public void shouldAuditData() {
    List<ErrorDetails> alertList = new ArrayList();
    auditService.auditData(alertList);
}

ОШИБКА

java.lang.NullPointerException
    at java.util.concurrent.CompletableFuture.screenExecutor(CompletableFuture.java:415)
    at java.util.concurrent.CompletableFuture.runAsync(CompletableFuture.java:1858)
    at com.service.impl.AuditService.auditData(AuditService.java:15)
    at com.service.impl.AuditServiceTest.shouldAuditData(AuditServiceTest.java:249)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    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.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    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.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Ответы [ 2 ]

2 голосов
/ 16 мая 2019

Вам нужно проверить свою логику, и вам не нужно высмеивать статический метод CompletableFuture.runAsync(...). Таким образом, ваш тест должен выглядеть как обычный тест за исключением того, что вам нужно подождать некоторое время, чтобы убедиться, что асинхронный код выполняется, потому что он не выполняется в одном потоке. Итак, на данный момент я приведу вам пример, который вы можете использовать с Thread.sleep(), что не является хорошим соглашением, в дополнительном вопросе вы можете спросить, как избежать использования Thread.sleep().

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

@RunWith(MockitoJUnitRunner.class)
public class AuditServiceTest {

    @Mock
    Service serviceMock;

    @Test
    public void shouldAuditData() {
        AuditService auditService = new AuditService(serviceMock);
        List<Object> alertList = new ArrayList();
        auditService.auditData(alertList);
        // you can wait with Thread.sleep() 
        // because the execution is asynchronous
        Mockito.verify(serviceMock).method1();
        Mockito.verify(serviceMock, Mockito.never()).method2();
    }
}

class AuditService {

    Executor existingThreadPool = Executors.newSingleThreadExecutor();
    Service service;

    public AuditService(Service service) {
        this.service = service;
    }

    public void auditData(List<Object> alertList) {
        CompletableFuture.runAsync(() -> {
            if (alertList.isEmpty()) {
                service.method1();
            } else {
                service.method2();
            }
        }, existingThreadPool);
    }
}
class Service {
    public void method1(){};
    public void method2(){};
}
0 голосов
/ 16 мая 2019

в классе AuditService, Executor подключается автоматически. это идеальная установка для юнит-тестов. вам нужно создать отдельную конфигурацию для теста, и реализация Executor должна быть встроенным исполнителем (вы можете предоставить собственную реализацию, которая вызывает runnable.run в том же вызывающем потоке). Для этого можно использовать некоторые реализации, предусмотренные spring-test. Например: AbstractJUnit4SpringContextTests

Если вам не нравится поддержка Spring-Test, теперь вы внедрили фиктивный Executor в AuditService. так что вы можете смоделировать метод execute с предоставлением пользовательского stub.Answer и выполнить runnable.run.

Mockito.doAnswer(new Answer() {
      public Object answer(InvocationOnMock invocation) {
        Object[] args = invocation.getArguments();
        ((Runnable)args[0]).run();
        return null; // void method, so return null
      }
    }).when(executor).execute(Mockito.any(Runnable.class));
...