【问题标题】:Getting NotAMockException on the below Test Case在以下测试用例中获取 NotAMockException
【发布时间】:2020-11-07 06:46:58
【问题描述】:

我尝试运行以下测试并面临NotAMock 异常,不知道如何解决它。我一直在尝试阅读不能模拟被测类方法的概念,但我无法明确这一主题。如果有人能以我自己的例子解释为什么,我希望能更好地理解它。

我尝试了各种方法来更改单元或集成测试设置的@RunWith 运行器,或者使用@Spy 而不是@Mock 或没有@Autowired 等,但要么面临dao Null Pointer,要么不是Mock Exception。

我应该使用另一个类并在该类中注入Listener 并模拟侦听器以实现能够模拟方法和动态捕获参数的功能。这会起作用,因为它不再是被测试的类,因此可以模拟方法吗?如果是这样,这是如何实现的。如果没有,什么是正确的方法。我的感觉是将听众转移到另一个班级只会扩展我当前无法模拟但无法解决的问题。但是,我不确定正确的结果是什么。

@Component
public class FileEventListener implements ApplicationListener<FileEvent> {

    @Autowired private FetchFileDetailsDAO fileDao;//Dao is annotated with @Transactional

    @Override
    public void onApplicationEvent(FileEvent event) {
        fileDao.getDetailsForFile(event.fileName())
    }     
}
-----------------------------------------------------------------------------------------

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

@SpringBootTest(classes = TestApp.class)
@RunWith(SpringRunner.class)
public class TestClass {  
  
@Captor private ArgumentCaptor<Object> captor;
@Mock @Autowired private FetchFileDetailsDAO dao;
@InjectMocks @Autowired private FileEventListener listener;

@Before
public void setup() throws IOException {
    MockitoAnnotations.initMocks(this);
}

@Test
@Transactional
@Rollback(true)
public void test() throws Exception {
    FileEvent ev = new FileEvent();
    ...
    listener.onApplicationEvent(ev);
    verify(dao, times(1)).getDetailsForFile((String)captor.capture())
}

【问题讨论】:

  • 此外,dao 本身具有 JbdcTemplate Autowired 依赖项。我无法实现 Spring Autowiring 和 Dependency Object(Ex: dao) 方法 mocking/spying 组合,这会给出 Null PointerNotAMock 或方法或 Actually zero interactions with the method 异常。

标签: java mockito junit4 spring-boot-test


【解决方案1】:

你把事情搞混了。 @Mock@MockBean 之间有一个重要的区别。

如果你想编写一个没有任何 Spring Context 支持的单元测试(比如@SpringBootTest@DataJpaTest 等),你可以使用第一个注解。对于此类测试,您可以使用@Mock@InjectMocks

当您编写集成测试时(您从 @SpringBootTest 开始整个上下文),您在测试中使用托管 Spring bean。因此,您不再编写 unit 测试了。

如果你想在你的 Spring 测试上下文中用它的模拟版本替换一个 Spring bean,你必须使用 @MockBean:

@SpringBootTest(classes = TestApp.class)
@RunWith(SpringRunner.class)
@RunWith(MockitoJUnitRunner.class) // will do the Captor initialization for you
public class TestClass {  

  @Captor 
  private ArgumentCaptor<Object> captor;

  @MockBean 
  private FetchFileDetailsDAO dao;

  @Autowired 
  private FileEventListener listener;


  @Test
  @Transactional
  @Rollback(true)
  public void test() throws Exception {
    FileEvent ev = new FileEvent();
    // ...
    listener.onApplicationEvent(ev);
    verify(dao, times(1)).getDetailsForFile((String)captor.capture())
  }

然而对于这个测试来说,开始整个上下文是恕我直言矫枉过正。你最好用just JUnit 和 Mockito 编写一个好的旧单元测试。

除此之外,我还会重新考虑您当前的测试对您的项目有什么好处,因为它实际上是在复制业务逻辑。也许还有更多的代码在这里没有。

您可以找到difference between @Mock and @MockBean in this article 的更详细摘要。

【讨论】:

    【解决方案2】:

    我认为问题出在下面一行

    @Mock @Autowired private FetchFileDetailsDAOImpl dao;
    

    改用@Mock private FetchFileDetailsDAOImpl dao;

    【讨论】:

    • 这给出了以下错误:实际上,与这个模拟 dao.getDetailsForFile( ); 的交互为零
    • 您是否使用了正确的导入?也许检查javacodegeeks.com/2014/01/… ...我假设异常在“verify(dao, times(1)).getDetailsForFile((String)captor.capture())”行中,对吗?
    • 是的,这是我得到的例外。
    • 我在代码中添加了import语句,请检查一下。
    • 导入看起来正确,我会尝试从类中删除 @SpringBootTest(classes = TestApp.class) @RunWith(SpringRunner.class) 注释(链接页面上的测试没有这个注释)..和提到的@Autowired
    猜你喜欢
    • 2012-01-26
    • 2013-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    相关资源
    最近更新 更多