Mockito初级学习

标签:mockito


使用Mockito来Mock对象

有两种方法来mock对象,1)使用静态方法: mock();2) 使用注解:@Mock

  • mock()
@Test
public void givenCountMethodMocked_WhenCountInvoked_ThenMockedValueReturned() {
    UserRepository localMockRepository = Mockito.mock(UserRepository.class);
    Mockito.when(localMockRepository.count()).thenReturn(111L);
 
    long userCount = localMockRepository.count();
 
    Assert.assertEquals(111L, userCount);
    Mockito.verify(localMockRepository).count();
}
  • @Mock
    • 采用@Rule注解来调用MockitoAnnotations.initMocks(this)
    • 采用@RunWith(MockitoJUnitRunner.class)
//实例1
import static org.mockito.Mockito.*;

public class MockitoTest  {

    @Mock
    MyDatabase databaseMock; 


    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); 


    @Test
    public void testQuery()  {
        ClassToTest t  = new ClassToTest(databaseMock); 

        boolean check = t.query("* from t"); 

        assertTrue(check); 

        verify(databaseMock).query("* from t"); 

    }
}
//实例2
@RunWith(MockitoJUnitRunner.class)
public class MockAnnotationUnitTest {
     
    @Mock
    UserRepository mockRepository;
     
    @Test
    public void givenCountMethodMocked_WhenCountInvoked_ThenMockValueReturned() {
        Mockito.when(mockRepository.count()).thenReturn(123L);
 
        long userCount = mockRepository.count();
 
        Assert.assertEquals(123L, userCount);
        Mockito.verify(mockRepository).count();
    }
}

Configuring mocks

  • "when thenReturn"和"when thenThrow
  • "doReturn when"和"doThrow when"

The doReturn(…​).when(…​).methodCall call chain works similar to when(…​.).thenReturn(…​.). It is useful for mocking methods which give an exception during a call.

使用Spy来包装java对象

@spy或者spy()方法被用来包装一个真实的对象。

  • spy()
@Test
public void whenNotUseSpyAnnotation_thenCorrect() {
    List spyList = Mockito.spy(new ArrayList());
     
    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());
}
  • @spy
@Spy
List spiedList = new ArrayList();
 
@Test
public void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() {
    spiedList.add("one");
    spiedList.add("two");
 
    Mockito.verify(spiedList).add("one");
    Mockito.verify(spiedList).add("two");
 
    assertEquals(2, spiedList.size());
 
    Mockito.doReturn(100).when(spiedList).size();
    assertEquals(100, spiedList.size());
}

在这个例子中,使用真实的方法spiedList.add()来给spiedList增加元素。

verify的用途

import static org.mockito.Mockito.*;

@Test
public void testVerify()  {
    // create and configure mock
    MyClass test = Mockito.mock(MyClass.class);
    when(test.getUniqueId()).thenReturn(43);


    // call method testing on the mock with parameter 12
    test.testing(12);
    test.getUniqueId();
    test.getUniqueId();


    // now check if method testing was called with the parameter 12
    verify(test).testing(ArgumentMatchers.eq(12));

    // was the method called twice?
    verify(test, times(2)).getUniqueId();

    // other alternatives for verifiying the number of method calls for a method
    verify(test, never()).someMethod("never called");
    verify(test, atLeastOnce()).someMethod("called at least once");
    verify(test, atLeast(2)).someMethod("called at least twice");
    verify(test, times(5)).someMethod("called five times");
    verify(test, atMost(3)).someMethod("called at most 3 times");
    // This let's you check that no other methods where called on this object.
    // You call it after you have verified the expected method calls.
    verifyNoMoreInteractions(test);
}

@injectMock

若某个class中有依赖的属性或者方法,在创建此class实例时,使用@InjectMocks来将mock注入。例如,我们有这样一个类:

public class ArticleManager {
    private User user;
    private ArticleDatabase database;

    public ArticleManager(User user, ArticleDatabase database) {
        super();
        this.user = user;
        this.database = database;
    }

    public void initialize() {
        database.addListener(new ArticleListener());
    }
}

这个类可通过Mockito来被创建,它的依赖也能被mock填充。

@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest  {

       @Mock ArticleCalculator calculator;
       @Mock ArticleDatabase database;
       @Mock User user;

       @Spy private UserProvider userProvider = new ConsumerUserProvider();

       @InjectMocks private ArticleManager manager; 

       @Test public void shouldDoSomething() {
           // calls addListener with an instance of ArticleListener
           manager.initialize();

           // validate that addListener was called
           verify(database).addListener(any(ArticleListener.class));
       }
}

捕获参数

ArgumentCaptor类允许在验证期间访问方法调用的参数。采用@Captor来实现。

import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import java.util.Arrays;
import java.util.List;

import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

public class MockitoTests {
    
    @Rule
    public MockitoRule rule = MockitoJUnit.rule();
    
    @Captor
    private ArgumentCaptor> captor;
    
    @Test
    public final void shouldContainCertainListItem() {
        List asList = Arrays.asList("someElement_test", "someElement");
        final List mockedList = mock(List.class);
        mockedList.addAll(asList);
    
        verify(mockedList).addAll(captor.capture());
        final List capturedArgument = captor.getValue();
        assertThat(capturedArgument, hasItem("someElement"));
    }
}

上述代码首先创建了一个参数列表,然后mock了一个List对象通过调用addAll函数来将参数添加到mockedList中。使用verify来验证mockedList调用addAll函数时,利用captor捕捉参数。captor是一个ArgumentCaptor实例,存储的是List类型的数据。最后,通过captor.getValue()来获得捕获的参数。

mock final类

java中的final关键字可以用来修饰变量、方法和类。final修饰变量,此变量是不能被修改的;final修饰方法,此方法不能被重写的(override);final修饰类后,此类不能被继承。下面给出一个例子来说明如何mock final类:

final class FinalClassDemo {
    public final String finalMethod() {
        return "something";
    }
}

@Test
public final void mockFinalClassTest() {
    FinalClassDemo instance = new FinalClassDemo();
    
    FinalClassDemo mock = mock(FinalClassDemo.class);
    when(mock.finalMethod()).thenReturn("other things");
    
    assertNotEquals(mock.finalMethod(), instance.finalMethod());
}

注意到,在对final类进行测试时,测试方法也是final的。

以前遇到过使用mock的实例

TWU期间的SpingBoot的Workshop,我们在Spring项目中用到类Mockito。但是,对于Spring项目,我们使用@MockBean注解来给Spring应用添加mock对象。下面的例子是Spring应用中,对于controller层进行测试的测试代码。由于controller层和service层存在依赖,因此需要mock service层的对象来进行测试。

@RunWith(SpringRunner.class)
@WebMvcTest(ProductController.class)
public class ProductControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private ProductService productService;

    @Test
    public void should_return_201_and_location_when_creating_product() throws Exception {
        //given
        Product product = new Product();
        product.setName("ice peak");

        Product createdProdcut = new Product();
        createdProdcut.setId("id1");
        createdProdcut.setName("ice peak");

        when(productService.create(refEq(product))).thenReturn(createdProdcut);

        mockMvc.perform(post("/products")
                .accept(MediaType.APPLICATION_JSON)
                .param("name","ice peak"))
                .andExpect(status().isCreated())
                .andExpect(header().string("location",containsString("/products/id1")));
    }
}

可以看到,在spring中我们使用注解@RunWith(SpringRunner.class)。对于service层的mock,使用的注解是@MockBean
注意到,我们使用mockMvc来进行测试。

你可能感兴趣的:(Mockito初级学习)