【问题标题】:Mokcito not mocking the DAO layerMockito 不模拟 DAO 层
【发布时间】:2019-11-08 12:39:27
【问题描述】:

我有一个 Spring MVC 应用程序。它有Controller、Service和Dao。我想通过使用 Mockito 模拟 DAO 层来仅测试控制器和服务。

我的控制器类:

@Controller
@RequestMapping(value="/audit")
public class AuditController {

   @Autowired
   AuditService auditService;

   ...
}

我的服务类:

@Service
public class AuditService {

   @Autowired
   AuditDao auditDao;

   ....
}

我的测试课:

@RunWith(SptringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/dispatcher-servlet.xml", "spring-context.xml"})
@WebAppConfiguration
public class AuditControllerTest {

   private MockMvc mockMvc;

   @Mock
   AuditDao auditDao;

   @Autowired
   private WebApplicationContext webApplicationContext;

   @Before
   public void setUp() {
       MockitAnnotations.initMocks(this);
       mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
   }


  @Test
  public void testGetAudit() {

      Mockito.when(auditDao.getAudit(Mockito.any(Long.class))).thenReturn(new Audit(1L));
      mockMvc.perform(get("/audit/{id}", "1")).andExpect(status().isOk());
  }
}

问题: 它通过自动连接的控制器和服务执行调用。但是,从 Service 中,DAO 调用将转到真正的 DAO,而不是 Mocked DAO。

  1. 我知道 DAO 自动连接到真正的 Dao,但我不确定如何用测试中的 Mock 替换该 Dao。

  2. 将 Dao 保留在控制器中并在控制器中使用 @InjectMock 可以正常工作,但我想将 Dao 保留在 Service 中并仅测试控制器和 Service,但单独模拟 Dao。

  3. 我怀疑此问题与上下文(Web 应用程序上下文和 MockMvc 上下文)有关,但我不确定如何解决。

任何帮助将不胜感激。提前致谢。

【问题讨论】:

  • 可能对使用的某些术语有误解,因为我认为这里有一些值得怀疑的设计选择。我建议审查当前的设计以遵循更可靠的方法。
  • @Nkosi 你能举一些具体的例子吗?
  • 好的,名称更改,它改变了我对所用术语的原始陈述。关于我的设计声明,Autowired 字段隐藏了类依赖项。您对实际调用的 dao 的评估是准确的,所以我正在调查。
  • 等等。您在服务上尝试过@InjectMock 吗?
  • 同时一些有趣的阅读tedvinke.wordpress.com/2014/02/13/…

标签: spring-mvc junit mockito


【解决方案1】:

首先我建议避免使用Autowired 字段,并让您通过构造函数依赖项显式公开它们的依赖项

控制器类:

@Controller
@RequestMapping(value="/audit")
public class AuditController {
    private final AuditService auditService;

    @Autowired
    public AuditController(AuditService auditService) {
        this.auditService = auditService
    }

    //...
}

服务类:

@Service
public class AuditService {            
    private final AuditDao auditDao;

    @Autowired
    public AuditService(AuditDao auditDao) {
        this.auditDao = auditDao;
    }

    //....
}

我在想一些类似的事情

@RunWith(SptringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/dispatcher-servlet.xml", "spring-context.xml"})
@WebAppConfiguration
public class AuditControllerTest {

    private MockMvc mockMvc;

    @Mock
    AuditDao auditDao;

    @InjectMock
    AuditService auditService;

    @Before
    public void setUp() {
        MockitAnnotations.initMocks(this);
        AuditController controller = new AuditController (auditService);
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }

    @Test
    public void testGetAudit() {

      Mockito.when(auditDao.getAudit(Mockito.any(Long.class))).thenReturn(new Audit(1L));
      mockMvc.perform(get("/audit/{id}", "1")).andExpect(status().isOk());
    }
}

但不确定它在行使时是否会按预期运行。

【讨论】:

  • 我试过了,它仍然调用真正的 DAO 而不是模拟 DAO。
  • 我认为这里真正的问题是 DAO 自动连接到 MockMvc 上下文之外的真实 Dao,我们需要看看如何将它设置为 MockMvc 上下文中的模拟 dao,我不确定.不过,在测试方法中使用 Mockito.mock 也没有任何影响。
  • 你需要覆盖上下文中的bean。似乎有多种选择。一种选择似乎是创建一些新的仅测试弹簧配置,它定义了一个新的模拟 auditDao。如果这被标记为“主要”,那么将加载 2 个实例的事实应该不是问题。现在没有时间提供完整的解决方案。
  • @Nkosi 太棒了,您更新的解决方案成功了,而且很有意义。感谢负载。
猜你喜欢
  • 2019-10-04
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
  • 2016-05-26
  • 1970-01-01
  • 2018-12-22
  • 2021-03-15
  • 2016-03-15
相关资源
最近更新 更多