Java 在下面的测试用例中获取NotomockException

Java 在下面的测试用例中获取NotomockException,java,mockito,junit4,spring-boot-test,Java,Mockito,Junit4,Spring Boot Test,我试图运行下面的测试,但遇到了NotAMock异常,不确定如何解决它。我一直在试图理解这样一个概念,即被测试的类的方法不能被模仿,但我无法清楚地说明这个问题。如果有人能以我自己的例子来解释原因,我希望能更好地理解它 我尝试了各种方法来更改单元或集成测试设置的@RunWith运行程序,或者使用@Spy而不是@Mock,或者没有@Autowired等,但要么面对dao空指针,要么不是可变的模拟异常 我是否应该使用另一个类,在该类中插入侦听器,并模拟侦听器,以实现能够模拟方法和动态捕获参数的功能。因为

我试图运行下面的测试,但遇到了
NotAMock
异常,不确定如何解决它。我一直在试图理解这样一个概念,即被测试的类的方法不能被模仿,但我无法清楚地说明这个问题。如果有人能以我自己的例子来解释原因,我希望能更好地理解它

我尝试了各种方法来更改单元或集成测试设置的
@RunWith
运行程序,或者使用
@Spy
而不是
@Mock
,或者没有
@Autowired
等,但要么面对dao空指针,要么不是可变的模拟异常

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

@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())
}
@组件
公共类FileEventListener实现ApplicationListener{
@Autowired private FetchFileDetailsDAO fileDao;//Dao用@Transactional注释
@凌驾
ApplicationEvent(FileEvent)上的公共无效{
fileDao.getDetailsForFile(event.fileName())
}     
}
-----------------------------------------------------------------------------------------
导入org.junit.Before;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.mockito.ArgumentCaptor;
导入org.mockito.Captor;
导入org.mockito.InjectMocks;
导入org.mockito.Mock;
导入org.mockito.mockito;
导入org.mockito.MockitoAnnotations;
导入org.springframework.boot.test.context.SpringBootTest;
导入org.springframework.test.annotation.Rollback;
导入org.springframework.test.context.junit4.SpringRunner;
导入org.springframework.transaction.annotation.Transactional;
@SpringBootTest(类=TestApp.class)
@RunWith(SpringRunner.class)
公共类TestClass{
@捕获者私人辩论捕获者捕获者;
@Mock@Autowired private FetchFileDetailsDAO;
@InjectMocks@Autowired private FileEventListener监听器;
@以前
public void setup()引发IOException{
initMocks(this);
}
@试验
@交易的
@回滚(true)
public void test()引发异常{
FileEvent ev=新FileEvent();
...
侦听器.onApplicationEvent(ev);
验证(dao,times(1)).getDetailsForFile((字符串)captor.capture())
}

我认为问题出在以下几行

@Mock @Autowired private FetchFileDetailsDAOImpl dao;

试试
@Mock private FetchFileDetailsDAOImpl;
而不是你在这里把事情搞混了。在
@Mock
@MockBean
之间有一个重要的区别

如果您想在没有任何Spring上下文支持的情况下编写单元测试(比如说
@springbootest
@DataJpaTest
,等等),您可以使用第一个注释。对于此类测试,您可以使用
@Mock
@InjectMocks

在编写集成测试时(您使用
@SpringBootTest
启动整个上下文),您在测试中使用托管Springbeans。因此,您不再编写单元测试

如果要在Spring测试上下文中用模拟版本的Springbean替换Springbean,则必须使用
@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())
  }
@springbootest(classes=TestApp.class)
@RunWith(SpringRunner.class)
@RunWith(MockitoJUnitRunner.class)//将为您执行捕获器初始化
公共类TestClass{
@俘虏
私家侦探;
@蚕豆
私有FetchFileDetailsDAO-dao;
@自动连线
私有文件事件监听器;
@试验
@交易的
@回滚(true)
public void test()引发异常{
FileEvent ev=新FileEvent();
// ...
侦听器.onApplicationEvent(ev);
验证(dao,times(1)).getDetailsForFile((字符串)captor.capture())
}
但是,对于这个测试来说,从整个上下文开始是有点过火了。您最好只使用JUnit和Mockito编写一个好的旧单元测试

除此之外,我还会重新思考当前的测试会给项目带来什么好处,因为它实际上是复制了业务逻辑


您可以找到的更详细的摘要。

这给出了以下错误:实际上,与此模拟dao的交互为零。getDetailsForFile();是否使用了正确的导入?请检查…我假设异常在“verify(dao,times(1)).getDetailsForFile((String)captor.capture())”行中,是否正确?是的,这是我遇到的异常。我已将导入语句添加到代码中,请检查。导入看起来正确,我将尝试从类中删除@SpringBootTest(classes=TestApp.class)@RunWith(SpringRunner.class)批注(链接页上的测试没有此批注)..还有提到的@AutowiredAlso,dao本身就有JbdcTemplate自动连线依赖项。我无法实现Spring自动连线和依赖项对象(例如:dao)方法模拟/监视的组合,这会给出
Null指针
NotAMock
或方法或
与方法的交互实际上为零。