【问题标题】:How to mock several sequence calls如何模拟多个序列调用
【发布时间】:2018-02-22 15:22:32
【问题描述】:

我正在尝试编写一个测试,该测试将模拟对存储库的调用并调用 BloomFilter 管理器来检查值。我在测试中模拟以下序列调用时遇到问题:

Mockito.when(bloomFilterManager.getBloomFilter().mightContain(anyString()))
                .thenReturn(true);

整个测试:

@RunWith(SpringRunner.class)
@TestConfiguration
public class FooServiceTest {

  @Autowired
  private BloomFilterManager bloomFilterManager;

  @Autowired
  private FooService fooService;

  @MockBean
  private FooRepository fooRepository;

  @Before
  public void setUp() {
    Faker faker = new Faker();

    Foo foo = new Foo(
            faker.number().randomNumber(),
            faker.lorem().word(),
            faker.number().randomDigit(),
            new BigDecimal(Math.random()),
            Foo.PaymentStatus.PAID,
            faker.date().between(new Date(), DateUtils.addDays(new Date(), 13))
    );

    Mockito.when(fooRepository.findOne(anyString()))
            .thenReturn(foo);
    Mockito.when(bloomFilterManager.getBloomFilter().mightContain(anyString()))
            .thenReturn(true);
  }

  @Test
  public void whenValidName_thenEmployeeShouldBeFound() {
    String fooId = "100000000000001";
    Foo.PaymentStatus actualPaymentStatus = fooService.retrievePaymentStatus(fooId);

    assertEquals(Foo.PaymentStatus.PAID, actualPaymentStatus);
  }

  @TestConfiguration
  static class FooServiceTestContextConfiguration {
    @Bean
    public FooService fooService() {
      return new FooService();
    }

    @Bean
    public BloomFilterManager bloomFilterManager() {
      return new BloomFilterManager();
    }
  }
}

BloomFilterManager.class:

@Component
public class BloomFilterManager {

  private static final int EXPECTED_INSERTIONS = 500000000;
  private static final double FFP = 0.01;

  private BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset
                  ()),
          EXPECTED_INSERTIONS, FFP);

  public void populate(List<Foo> foos) {
    foos.stream().map(Foo::getId).forEach(i -> bloomFilter.put(i));
  }

  public BloomFilter<String> getBloomFilter(){
    return bloomFilter;
  }
}

BloomFilterManager在服务中的使用:

@Service
public class FooService implements IFooService {

  @Autowired
  private BloomFilterManager bloomFilterManager;

  @Autowired
  private FooRepository fooRepository;

  @Override
  public Foo.PaymentStatus retrievePaymentStatus(String fooId) {
    if (!bloomFilterManager.getBloomFilter().mightContain(fooId))
      return null;

    return fooRepository.findOne(fooId).getPaymentStatus();
  }
}

我在测试运行期间收到以下错误:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.


    at org.learn.unit.FooServiceTest.setUp(FooServiceTest.java:71)
    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.RunBefores.evaluate(RunBefores.java:24)
    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:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    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:191)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    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.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)

【问题讨论】:

  • bloomFilterManager 不是模拟,所以你不能使用when(bloomFilterManager.... 这就是错误消息when() requires an argument which has to be 'a method call on a mock'. 所说的
  • 嗯,好的,但也许 BloomFilterManagaer 类可以以最好的方式被覆盖,以便可以模拟它?
  • 如果BloomFilterManager 的注释是@Autowired 而不是@MockBean,为什么要模拟它?

标签: spring-boot mockito bloom-filter


【解决方案1】:

你的模拟是错误的。 Mockito 遵循一个非常简单的结构。你不能链接你的模拟调用。

Mockito.when(fooRepository.findOne(anyString())) .thenReturn(foo);

需要

Mockito.when(fooRepository).findOne(anyString()) .thenReturn(foo);

Mockito.when(bloomFilterManager.getBloomFilter().mightContain(anyString())) .thenReturn(true); }

需要。

Filter filter = Mockito.mock(Filter.class);
Mockito.when(bloomFilterManager).getBloomFilter().thenReturn(filter);
Mockito.when(filter).mightContain(anyString()).thenReturn(true);

【讨论】:

  • 试过这种方式,发现番石榴BloomFilter类是最终的,因为我不能模拟这个类。据我了解,只有正常使用bloomfilter的方法,而不是模拟,对吧?
猜你喜欢
  • 2021-11-04
  • 2019-12-06
  • 2012-06-12
  • 2018-11-12
  • 2022-01-26
  • 1970-01-01
  • 2020-09-12
  • 2021-07-04
相关资源
最近更新 更多