使用 mockito 和 Junit 进行单元测试时如何处理 Page

How to deal with Page while unit testing with mockito and Junit

我想用假数据模拟数据库调用,但我遇到了以下情况:

我的服务

public class MyService {
    // some stuff

    Page<SampleDto> sample = repo.findAllSample();

    // other stuff
}

我想用 when() 存根,但我做不到。我的测试是: 我的服务测试

public class MySampleTest {

    @Test
    void myTest() {
        // initialisation and all stuff

        when(myRepo.findAll()).thenReturn(......)
        // I want to pass 2 fake SampleDto from 
        // here but don't know how to do that
    }
}

解决此类任务通常有两个主要方向:

  1. 假对象
  2. 嘲讽

假对象 方法是在 lightweight/simple 情况下没有任何第三方库的简单实现你的回购:

public class FakeRepo implements Repo<T> {
   private final Collection<T> all;

   public FakeRepo(){
      this(Collections.emptySet());
   }

   public FakeRepo(Collection<T> all){
       this.all = all;
   }

   @Override
   public Collection<T> findAll(){
       return this.all;
   }
}

在你的测试中可能看起来像

@Test
public void justdoit(){
   MyService service = new MyService(
       new FakeRepo(Arrays.asList(1,2))
   );
   // test the service & methods
}

Mocking 允许您制作更复杂的解决方案。 请注意方法 Mockito.mock(ArrayList.class)Mockito.spy(new ArrayList<String>())。您需要使用 Mockito 引擎 assemble 您的复杂对象,例如 https://www.baeldung.com/mockito-annotations

@Test
public void whenNotUseMockAnnotation_thenCorrect() {
    List mockList = Mockito.mock(ArrayList.class);
    
    mockList.add("one");
    Mockito.verify(mockList).add("one");
    assertEquals(0, mockList.size());

    Mockito.when(mockList.size()).thenReturn(100);
    assertEquals(100, mockList.size());
}

@Test
public void whenNotUseSpyAnnotation_thenCorrect() {
    List<String> spyList = Mockito.spy(new ArrayList<String>());
    
    spyList.add("one");
    spyList.add("two");

    Mockito.verify(spyList).add("one");
    Mockito.verify(spyList).add("two");

    assertEquals(2, spyList.size());

    Mockito.doReturn(100).when(spyList).size();
    assertEquals(100, spyList.size());
}

只需创建您想要 returned 的内容并将其传递给 thenReturn()

在你的情况下它可能是这样的:

// I making this up, because you did not state what 'Page' actually is
var result = new Page();
result.add(new SampleDto(1));
result.add(new SampleDto(2));
when(myRepo.findAllSample()).thenReturn(result);

您可能无法执行此操作,具体取决于 Page 的实际实现,例如,如果这是一个 JPA Page。在这种情况下,您不应该真正 return Page 到您的服务中,而是将 JPA 存储库包装到一个 return 是 List<SampleDto>Set<SampleDto> 的适配器存储库中.否则,属于域的服务将依赖于基础结构代码(如 JPA)的实现细节,这很少是一个好主意。

如果需要在您的服务 class 中处理一些其他功能,您也可以模拟 Page 对象。假设您的服务 class 实际上是这样的:

public class MyService {
    @Resource
    private SampleRepository repo;

    public Page<SampleDto> findAllSample() {
        var sampleData = repo.findAllSample();
        // perhaps some operations with sample data and page
        return sampleData;
    }
}

那么测试 class 可能类似于 (JUnit4):

@RunWith(MockitoJUnitRunner.class)
public class MySampleTest {
    @Mock
    private SampleRepository repo;
    @Mock
    private Page<SampleDto> page;
    @InjectMocks
    private MyService myService;

    @Test
    public void test() {
    doReturn(page).when(repo).findAll();
    var listSampleDtos = List.of(new SampleDto()); // populate with what you need
    doReturn(listSampleDtos).when(page).getContent();
    var page = myService.findAllSample();
    // ... do the asserts, just as an example:
    verify(repo).findAll(); // called
    assertEquals(1, page.getContent().size());
    }

您可以模拟页面并制作示例对象。可能这就是您要搜索的确切答案。

我的样本测试

public class MySampleTest {

@Test
void myTest() {

    // initialisation and all stuff

    List<SampleDto> sampleDtos = new ArrayList<>();

    //now add any number of sample dto
    dtos.add(new SampleDto());

    //mock page class here
    Page page = mock(Page.class);

    //stub page.getContent
     when(page.getContent()).thenReturn(Collections.singletonList(sampleDtos));

    // No need to do this  when(myRepo.findAll()).thenReturn()
  
}

}