【问题标题】:Junit4 Mockito UnfinishedVerificationException TransactionManagerJunit4 Mockito UnfinishedVerificationException TransactionManager
【发布时间】:2014-08-15 20:46:49
【问题描述】:

当我开始在基于 Spring FW4 的 Java 应用程序中对一些控制器方法进行单元测试时,我遇到了一个复杂的问题。

我的 ApplicationConfig.java 使用 @Configuration 和 @EnableTransactionManagement(proxyTargetClass = true) 和一个公共控制器方法进行注释,我创建该方法是为了保存一个简单实体类的新对象,它是带有以下 ControllerTestClass 的 testet

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"classpath:/test-context.xml"})
@TransactionConfiguration(defaultRollback = true, transactionManager = "annotationDrivenTransactionManager")
public class TestController 
    @Autowired
    public MyClassService myClassServiceMock;

    protected MockMvc mockMvc;

    @Autowired
    protected WebApplicationContext webApplicationContext;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    };

    @org.junit.Before
    public void reset() {
        Mockito.reset(myClassServiceMock);
    }

    @org.junit.After
    public void after() { 
         verifyNoMoreInteractions(myClassServiceMock);
    }


    @Test
    public void testSaveObject() throws Exception {
        MyObject object = new MyObjectBuilder().withName("object").withDate("2014-08-15").build();
        when(myClassServiceMock.createObject(objectName, objectDate)).thenReturn(object);

        [.. mockMvcTest which works ... ]

        verify(myclassServiceMock, times(1)).createObject(objectName, objectDate);
    }
}

debug.log 的以下部分是我无法弄清楚问题的原因,但是当我删除@EnableTransactionManager-Annotation 时,没有发生错误......

2014-08-15_17:25:59.608 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Creating new transaction with name [a.b.c.MyClassService$$EnhancerByMockitoWithCGLIB$$cf62a86c.saveObject]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2014-08-15_17:25:59.608 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@513f39c] for JPA transaction
2014-08-15_17:25:59.616 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@320cac01]
2014-08-15_17:25:59.618 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
2014-08-15_17:25:59.618 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@513f39c]
2014-08-15_17:25:59.633 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@513f39c] after transaction
2014-08-15_17:25:59.633 [main] DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
2014-08-15_17:25:59.635 [main] DEBUG o.s.t.c.s.DirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@8f72029 testClass = MyControllerTest, testInstance = a.b.c.MyControllerTest@453204e6, testMethod = testSaveObject@MyClassControllerTest, testException = org.mockito.exceptions.misusing.UnfinishedVerificationException: 
Missing method call for verify(mock) here:
-> at a.b.c.MyClassService$$FastClassBySpringCGLIB$$809f2bf.invoke(<generated>)

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

我真的很感激一些帮助,因为我的古怪和研究已经进行了几天:(

谢谢

【问题讨论】:

    标签: mockito junit4 spring-4 transactionmanager


    【解决方案1】:

    首先,您没有在测试中初始化 Mockito。 Read this post

    您需要调用MockitoAnnotations.initMocks(),因为您已经在使用@RunWith(SpringJUnit4ClassRunner.class),并且您只能在一个类中指定一个跑步者。

    @Before
    public void reset() {
        MockitoAnnotations.initMocks(this);
        // Mockito.reset(myClassServiceMock);   <= remove this line
    }
    

    我认为您还想使用 @Mock 而不是 @Autowired 进行此模拟,以便您拥有一个 Mockito 模拟实例,然后您可以稍后调用 verify()。您还必须将myClassServiceMock 注入您的测试类(即控制器)

    @Mock
    public MyClassService myClassServiceMock;
    

    您可以删除对 Mockito.reset() 的调用,因为@Mock 将为每个测试方法创建一个新实例。

    如果您打算使用 @Autowired 并从应用程序上下文中检索 MyClassService 的实例,那么您将无法在其上调用任何 Mockito 方法,例如 verify()。

    我还希望 @TransactionConfiguration 不是必需的,因为您永远不会访问您的数据库(因为您正在模拟您的服务层),因此您可以将其删除。如果您在测试中访问数据库,那就另当别论了,但我无法从您提供的代码中看出这一点。

    【讨论】:

    • 这对我很有帮助,我的朋友!谢谢!我是 JUnit 的新手,到目前为止,我习惯于与优秀的测试开发人员一起工作。现在轮到我积累一些经验了。我从 Mockito 文档中得到了你的观点和理解,为什么它让我的生活更轻松。但是让我问一下,“您还必须将 myClassServiceMock 注入到您的测试类(即控制器)中”是什么意思?使用@Inject?
    • 假设您正在测试的控制器类称为MyController,那么我希望您的测试注入由@Mock 创建的myClassServiceMock。 MyController 如何获得它对 MyClassService 的引用?它是直接从应用程序上下文中查询它,还是@Autowired?
    • MockitoAnnotations.initMocks() 此行不初始化 mockito,它只是查找所有注释并将模拟对象注入所有 @Mock 字段。您可以使用 Mockito.mock() 代替注释
    猜你喜欢
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-05
    相关资源
    最近更新 更多