草庐IT

java - Mockito 抛出 UnfinishedVerificationException(可能与本地方法调用有关)

coder 2024-03-30 原文

我在运行测试用例时出现以下异常:

org.mockito.exceptions.misusing.UnfinishedVerificationException: 
Missing method call for verify(mock) here:
-> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Example of correct verification:
    verify(mock).doSomething()

Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.

    at com.bignibouX.tests.repository.member.MemberCachingIntegrationTest.testFindByEmail(MemberCachingIntegrationTest.java:61)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:81)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:215)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:81)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:60)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:67)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:161)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

测试用例有两个测试如下:

@ActiveProfiles(Profiles.TEST)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { FullIntegrationTestConfiguration.class, BaseTestConfiguration.class, MemberCachingIntegrationTest.Config.class })
public class MemberCachingIntegrationTest {

    private static final Member MEMBER_ONE = new Member();
    private static final Member MEMBER_TWO = new Member();

    @Autowired
    private MemberRepository memberRepositoryMock;

    @After
    public void validate() {
        validateMockitoUsage();
    }

    @Test
    public void testFindByEmail() {
        when(memberRepositoryMock.findByEmail(anyString())).thenReturn(MEMBER_ONE, MEMBER_TWO);

        Member firstInvocation = memberRepositoryMock.findByEmail("foo@foo.com");
        assertThat(firstInvocation, is(MEMBER_ONE));

        Member secondInvocation = memberRepositoryMock.findByEmail("foo@foo.com");
        assertThat(secondInvocation, is(MEMBER_ONE));

        verify(memberRepositoryMock, times(1)).findByEmail("foo@foo.com");

        Member thirdInvocation = memberRepositoryMock.findByEmail("bar@bar.com");
        assertThat(thirdInvocation, is(MEMBER_TWO));

        verify(memberRepositoryMock, times(1)).findByEmail("bar@bar.com");
    }

    @Test
    public void passingInexistentEmailToSendPasswordResetShouldNotCauseNPE() {
        fail("MemberRepository's findByEmail throws NPE if email not found in db! Reason: because cache was set up not to allow null values...");
        fail("Appropriate error page not displayed when above NPE is thrown!");
    }

    @Profile(Profiles.TEST)
    @Configuration
    static class Config {

        @Bean
        public MemberRepository memberRepositoryMock() {
            return mock(MemberRepository.class);
        }
    }
}

我的问题有两个:

  • 我不确定这里调用了什么:sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)... 它与反射和本地方法有关,但在我的例子中是哪个本地方法?
  • 我在使用 Mockito 时出了什么问题?

编辑:

@RooJpaRepository(domainType = Member.class)
public interface MemberRepository {

    @Cacheable(value = CacheConfiguration.DATABASE_CACHE_NAME)
    Member findByEmail(String email);

    @Cacheable(CacheConfiguration.DATABASE_CACHE_NAME)
    Member findByToken(String token);

    @CacheEvict(value = CacheConfiguration.DATABASE_CACHE_NAME, key = "#result.email")
    <S extends Member> S save(S entity);
}

编辑 2:

我已经调试了测试并包含了屏幕截图,这似乎证实了 macias 所说的:

org.springframework.aop.framework.ProxyFactory: 2 interfaces [com.bignibou.repository.member.MemberRepository, org.mockito.cglib.proxy.Factory]; 1 advisors [org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor: advice bean 'null']; targetSource [SingletonTargetSource for target object [com.bignibou.repository.member.MemberRepository$$EnhancerByMockitoWithCGLIB$$1b543cbe@4cca9ed4]]; proxyTargetClass=false; optimize=false; opaque=false; exposeProxy=false; frozen=false

编辑 3:要考虑的另一件事:如果我删除或注释掉测试中的最后一行和拆卸方法,即

verify(memberRepositoryMock, times(1)).findByEmail("bar@bar.com");

@After
public void validate() {
        validateMockitoUsage();
}

测试顺利通过....

edit 4:我实际上拼命尝试改编以下示例:https://stackoverflow.com/a/24229350/536299那是在另一篇文章中给我的。人们确实注意到模拟是 Autowiring 的,并且测试确实使用了 spring 上下文。有人可以帮助我正确地进行测试吗?

最佳答案

sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - 根据您提供的堆栈跟踪,mockito 在报告错误时有点困惑。它与您的问题并没有真正的关系,但无论如何这是 native 的 NativeMethodAccessorImpl.invoke0 (请参阅 grep code )。 SpringJUnit4ClassRunner 运行它,这就是它的工作方式,您无需关心。

现在谈谈您的真正问题,正如我在评论中所写,这是因为 Spring 将模拟对象包装到代理中。如果你添加

System.out.println(memberRepositoryMock.getClass());

您会在控制台中看到它不是模拟,而是那里的一些代理。 Mockito 只能 stub 模拟,所以这就是您收到错误的原因。

现在的问题可能是,如何解决这个问题。 首先,您的测试实际上并不是集成测试,因为您试图模拟存储库而不是真正测试数据访问的行为方式。在这种情况下,我会放弃使用 spring-test 而只是选择简单的 MockitoJUnitRunner。

更新:

好的,现在知道它实际上是要测试的缓存,我知道您需要用 Spring 缓存装饰模拟存储库,并且您的测试确实是一个集成测试。

这是如何完成的。提到的一点变化 frant.hartm proposal但不使用静态引用。我认为稍微自然一些。

@ActiveProfiles(Profiles.TEST)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { FullIntegrationTestConfiguration.class, BaseTestConfiguration.class, MemberCachingIntegrationTest.Config.class })
public class MemberCachingIntegrationTest {

    @Autowired
    private MemberRepository cachedRepository;

    @Autowired
    private MockProvider mockProvider;

    @After
    public void validate() {
        validateMockitoUsage();
    }

    @Test
    public void test() {
        when(mockProvider.get().findByEmail(anyString())).thenReturn("foo", "bar");

        String firstInvocation = cachedRepository.findByEmail("foo@foo.com");
        assertThat(firstInvocation, is("foo"));

        String secondInvocation = cachedRepository.findByEmail("foo@foo.com");
        assertThat(secondInvocation, is("foo"));

        verify(mockProvider.get(), times(1)).findByEmail("foo@foo.com");

        String thirdInvocation = cachedRepository.findByEmail("bar@bar.com");
        assertThat(thirdInvocation, is("bar"));

        verify(mockProvider.get(), times(1)).findByEmail("bar@bar.com");
    }

    @Configuration
    static class Config {

        private MemberRepository mockRepository = mock(MemberRepository.class);

        @Bean
        public MemberRepository cachedRepository() {
            return mockRepository;
        }

        @Bean
        public MockProvider mockProvider() {
            return new MockProvider(mockRepository);
        }

    }

    public static class MockProvider {

        private final MemberRepository repository;

        public MockProvider(MemberRepository repository) {
            this.repository = repository;
        }

        public MemberRepository get() {
            return this.repository;
        }

    }
}

注意:存储库返回字符串而不是成员以获得更清晰的示例

关于java - Mockito 抛出 UnfinishedVerificationException(可能与本地方法调用有关),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24467675/

有关java - Mockito 抛出 UnfinishedVerificationException(可能与本地方法调用有关)的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  6. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  7. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  8. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  9. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  10. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

随机推荐