有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Mockito中测试使用ExecutorService而不使用timeout的代码?

我有课

public class FeedServiceImpl implements FeedService {
    private final Map<FeedType, FeedStrategy> strategyByType;
    private final ExecutorService executorService = Executors.newSingleThreadExecutor(); 

    public FeedServiceImpl(Map<FeedType, FeedStrategy> strategyByType) {
        if (strategyByType.isEmpty()) throw new IllegalArgumentException("strategyByType map is empty");
        this.strategyByType = strategyByType;
    }

    @Override
    public void feed(LocalDate feedDate, FeedType feedType, String uuid) {
        if (!strategyByType.containsKey(feedType)) {
            throw new IllegalArgumentException("Not supported feedType: " + feedType);
        }
        executorService.submit(() -> runFeed(feedType, feedDate, uuid));
    }


    private FeedTaskResult runFeed(FeedType feedType, LocalDate feedDate, String uuid) {
        return strategyByType.get(feedType).feed(feedDate, uuid);
    }
}

当我调用feed方法时,如何用Mockito验证strategyByType.get(feedType).feed(feedDate, uuid)是否被调用

@RunWith(MockitoJUnitRunner.class)
public class FeedServiceImplTest {
    private LocalDate date = new LocalDate();
    private String uuid = "UUID";

    private FeedService service;
    private Map<FeedType, FeedStrategy> strategyByType;

    @Before
    public void setUp() {
        strategyByType = strategyByTypeFrom(TRADEHUB);
        service = new FeedServiceImpl(strategyByType);
    }

    private Map<FeedType, FeedStrategy> strategyByTypeFrom(FeedSource feedSource) {
        return bySource(feedSource).stream().collect(toMap(identity(), feedType -> mock(FeedStrategy.class)));
    }

    @Test
    public void feedTest() {
        service.feed(date, TH_CREDIT, uuid);
        verify(strategyByType.get(TH_CREDIT), timeout(100)).feed(date, uuid);
    }
}

这是我的版本。但我不想使用Mockito超时方法。我认为这不是一个好的解决办法。请帮帮我


共 (4) 个答案

  1. # 1 楼答案

    @Per-Huss答案有一点改进,因此您不必更改构造函数,您可以使用ReflectionTestUtils类,该类是spring test包的一部分

    @Before
    public void setUp() {
        strategyByType = strategyByTypeFrom(TRADEHUB);
        service = new FeedServiceImpl(strategyByType);
        ReflectionTestUtils.setField(service , "executorService", MoreExecutors.newDirectExecutorService());
    }
    

    现在在测试中,Executor服务将实现更多Executor。newDirectExecutorService()而不是执行器。newSingleThreadExecutor()

  2. # 2 楼答案

    如果您想运行一个realFeedStrategy(而不是另一个答案中建议的模拟线程),那么您需要一种方法,让FeedStrategy以某种方式指示测试线程何时完成。例如,通过使用CountDownLatch或设置测试可以等待的标志

    public class FeedStrategy {
    
        private boolean finished;
    
        public void feed(...) {
            ...
            this.finished = true;
        }
    
        public boolean isFinished() {
            return this.finished;
        }
    }
    

    或者也许FeedStrategy有一些副作用,你可以等待

    如果上述任何一项为真,那么您可以使用Awaitility实现一个服务生。例如:

        @Test
        public void aTest() {
            // run your test
    
            // wait for completion
            await().atMost(100, MILLISECONDS).until(feedStrategyHasCompleted());
    
            // assert 
            // ...
        }
    
        private Callable<Boolean> feedStrategyHasCompleted() {
            return new Callable<Boolean>() {
                public Boolean call() throws Exception {
                    // return true if your condition has been met
                    return ...;
                }
            };
        }
    
  3. # 3 楼答案

    当我测试依赖于执行器的代码时,我通常尝试使用一个执行器实现,该执行器实现在提交的同一线程中立即运行任务,以消除多线程处理的所有麻烦。也许您可以为FeedServiceImpl类添加另一个构造函数,让您提供自己的执行器?GoogleGuava库有一个MoreExecutors.directExecutor()方法,它将返回这样一个执行器。这意味着您的测试设置将更改为:

    service = new FeedServiceImpl(strategyByType, MoreExecutors.directExecutor());
    

    测试代码的其余部分应按原样工作,您可以安全地删除超时验证模式参数

  4. # 4 楼答案

    你需要为FeedStrategy做一个模拟。类对您的测试可见,以便您能够验证FeedStrategy是否正确。已调用提要方法:

    @RunWith(MockitoJUnitRunner.class)
    public class FeedServiceImplTest {
    private LocalDate date = new LocalDate();
    private String uuid = "UUID";
    
    private FeedService service;
    private Map<FeedType, FeedStrategy> strategyByType;
    private FeedStrategy feedStrategyMock;
    
    
    @Before
    public void setUp() {
        strategyByType = strategyByTypeFrom(TRADEHUB);
        service = new FeedServiceImpl(strategyByType);
        feedStrategyMock = Mockito.mock();
    }
    
    private Map<FeedType, FeedStrategy> strategyByTypeFrom(FeedSource feedSource) {
        return bySource(feedSource).stream().collect(toMap(identity(), feedType -> feedStrategyMock));
    }
    
    @Test
    public void feedTest() {
        service.feed(date, TH_CREDIT, uuid);
        verify(feedStrategyMock).feed(date, uuid);
    }
    }