单元测试如何使用 Mockito 模拟存储库
Posted
技术标签:
【中文标题】单元测试如何使用 Mockito 模拟存储库【英文标题】:Unit Tests How to Mock Repository Using Mockito 【发布时间】:2018-12-05 19:11:40 【问题描述】:我在存根存储库时遇到问题。有人建议我只创建另一个 application.properties(我还没有这样做)并使用像 H2 这样的内存数据库。我想知道我是否可以只存根调用,所以当调用 myDataService.findById(id) 而不是尝试从数据库中获取它时,只能返回一个模拟对象?
一般来说,我是为单元测试和 Spring Boot 编写模拟程序的新手,所以也许我遗漏了一些东西。下面的代码(试图简化并使名称通用,以便在此处发布)。
我的测试课
public class MyServiceImplTest
private MyDataService myDataService;
private NyService myService;
private MyRepository myRepository;
@Before
public void setUp()
myDataService = Mockito.mock(MyDataServiceImpl.class);
myService = new MyServiceImpl(myDataService);
@Test
public void getById_ValidId()
doReturn(MyMockData.getMyObject()).when(myDataService).findById("1");
when(myService.getById("1")).thenReturn(MyMockData.getMyObject());
MyObject myObject = myService.getById("1");
//Whatever asserts need to be done on the object myObject
用于对数据层进行服务调用的类
@Service
public class MyServiceImpl implements MyService
MyDataService myDataService;
@Autowired
public MyServiceImpl(MyDataService myDataService)
this.myDataService = myDataService;
@Override
public MyObject getById(String id)
if(id == null || id == "")
throw new InvalidRequestException("Invalid Identifier");
MyObject myObj;
try
myObj = myDataService.findById(id);
catch(Exception ex)
throw new SystemException("Internal Server Error");
return myObj;
这是我在测试中遇到问题的地方。当调用 findById() 方法时,变量 repository 为空,因此在尝试执行 repository.findOne(id) 时会抛出异常。这是我试图模拟的,但存储库给我带来了问题。
@Repository
@Qualifier("MyRepo")
public class MyDataServiceImpl
@PersistenceContext
private EntityManager em;
private MyRepository repository;
@Autowired
public MyDataServiceImpl(MyRepository repository)
super(repository);
this.repository = repository;
public MyObject findById(String id)
P persitentObject = repository.findOne(id);
//Calls to map what persitentObject holds to MyObject and returns a MyObject
这里的 MyRepository 代码只是为了显示它是一个扩展 CrudRepository 的空接口
public interface MyRepository extends CrudRepository<MyObjectPO, String>, JpaSpecificationExecutor<MyObjectPO>
【问题讨论】:
我没有关注你所做的一切,但我认为你希望myRepository
成为一个模拟对象,而 myDataService
成为一个内部包含模拟存储库的真实对象。如果这就是你想要的,你可以试试myRepository = mock(MyRepository.class); myDataService = new DataServiceImpl(myRepository);
。还是我误解了您要做什么?
是的,这正是我想要做的!我想我看了一会儿之后也开始迷惑了。
【参考方案1】:
首先让我说你是在正确的轨道上使用构造函数注入而不是字段注入(这使得使用模拟编写测试变得更加简单)。
public class MyServiceImplTest
private MyDataService myDataService;
private NyService myService;
@Mock
private MyRepository myRepository;
@Before
public void setUp()
MockitoAnnotations.initMocks(this); // this is needed for inititalizytion of mocks, if you use @Mock
myDataService = new MyDataServiceImpl(myRepository);
myService = new MyServiceImpl(myDataService);
@Test
public void getById_ValidId()
doReturn(someMockData).when(myRepository).findOne("1");
MyObject myObject = myService.getById("1");
//Whatever asserts need to be done on the object myObject
调用一直从您的服务 --> dataService 进行。但只有您的存储库调用会被模拟。 通过这种方式,您可以控制和测试类的所有其他部分(服务和数据服务)并仅模拟存储库调用。
【讨论】:
非常感谢@pvpkiran!这正是我一直在寻找并且正在努力弄清楚的!一旦我看到解决方案就这么简单! 我不需要使用MockitoAnnotations.initMocks(this)
进行非常相似的测试以上是关于单元测试如何使用 Mockito 模拟存储库的主要内容,如果未能解决你的问题,请参考以下文章