Android单元测试系列-Mock之Mockito
Posted Chris_166
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android单元测试系列-Mock之Mockito相关的知识,希望对你有一定的参考价值。
一、官网
Mockito:
https://github.com/mockito/mockito
为什么要用mock:解决测试类对其他类的依赖。在实际的测试过程中,有些需要被测试的方法对其他类对象或变量有依赖,如果不初始化的话,很容易出现NP导致无法顺利的继续测试,这个时候就需要mock这些对象来解决了。
二、Demo示例
参考android Developer中提到的示例来说明Mockito用法。
1. 目录结构
2. 被测试的类
// gradle引入
dependencies
// test目录
testImplementation 'org.mockito:mockito-core:4.4.0'
// androidTest目录
//androidTestImplementation "org.mockito:mockito-android:4.4.0"
// 被测试类为 SharedPreferencesHelper
package com.fanff.unittestdemo.mockdemo;
import android.content.SharedPreferences;
import java.util.Calendar;
/**
* 参考Google官网示例:https://github.com/android/testing-samples/tree/master/unit/BasicSample
*/
public class SharedPreferencesHelper
// Keys for saving values in SharedPreferences.
static final String KEY_NAME = "key_name";
static final String KEY_DOB = "key_dob_millis";
static final String KEY_EMAIL = "key_email";
private final SharedPreferences mSharedPreferences;
public SharedPreferencesHelper(SharedPreferences sharedPreferences)
mSharedPreferences = sharedPreferences;
public boolean savePersonalInfo(SharedPreferenceEntry sharedPreferenceEntry)
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(KEY_NAME, sharedPreferenceEntry.getName());
editor.putLong(KEY_DOB, sharedPreferenceEntry.getDateOfBirth().getTimeInMillis());
editor.putString(KEY_EMAIL, sharedPreferenceEntry.getEmail());
// Commit changes to SharedPreferences.
return editor.commit();
public SharedPreferenceEntry getPersonalInfo()
// Get data from the SharedPreferences.
String name = mSharedPreferences.getString(KEY_NAME, "");
Long dobMillis =
mSharedPreferences.getLong(KEY_DOB, Calendar.getInstance().getTimeInMillis());
Calendar dateOfBirth = Calendar.getInstance();
dateOfBirth.setTimeInMillis(dobMillis);
String email = mSharedPreferences.getString(KEY_EMAIL, "");
// Create and fill a SharedPreferenceEntry model object.
return new SharedPreferenceEntry(name, dateOfBirth, email);
package com.fanff.unittestdemo.mockdemo;
import java.util.Calendar;
public class SharedPreferenceEntry
// Name of the user.
private final String mName;
// Date of Birth of the user.
private final Calendar mDateOfBirth;
// Email address of the user.
private final String mEmail;
public SharedPreferenceEntry(String name, Calendar dateOfBirth, String email)
mName = name;
mDateOfBirth = dateOfBirth;
mEmail = email;
public String getName()
return mName;
public Calendar getDateOfBirth()
return mDateOfBirth;
public String getEmail()
return mEmail;
3. 测试类
Q:只想测试SharedPreferencesHelper#savePersonalInfo()是否有调用Editor#commit()
A:但是savePersonalInfo()这个方法中需要依赖的对象有SharedPreferenceEntry、Editor,想要绕开这些对象的创建就需要用到mock了。
public boolean savePersonalInfo(SharedPreferenceEntry sharedPreferenceEntry)
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(KEY_NAME, sharedPreferenceEntry.getName());
editor.putLong(KEY_DOB, sharedPreferenceEntry.getDateOfBirth().getTimeInMillis());
editor.putString(KEY_EMAIL, sharedPreferenceEntry.getEmail());
// Commit changes to SharedPreferences.
return editor.commit();
// 单元测试代码
package com.fanff.unittestdemo.mockdemo;
import android.content.SharedPreferences;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.Calendar;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
public class SharedPreferencesHelperTest
@Before
public void setUp() throws Exception
@After
public void tearDown() throws Exception
@Test
public void testSavePersonalInfo()
// Mock SharedPreferences对象作为SharedPreferencesHelper构造方法的参数
SharedPreferences sharedPreferences = Mockito.mock(SharedPreferences.class);
SharedPreferencesHelper sharedPreferencesHelper =
new SharedPreferencesHelper(sharedPreferences);
// Mock SharedPreferenceEntry对象作为savePersonalInfo方法的参数
SharedPreferenceEntry sharedPreferenceEntry = Mockito.mock(SharedPreferenceEntry.class);
// Mock SharedPreferences.Editor对象作为savePersonalInfo方法里的局部变量
SharedPreferences.Editor editor = Mockito.mock(SharedPreferences.Editor.class);
// Mock savePersonalInfo()方法内部的执行流程
when(sharedPreferences.edit()).thenReturn(editor);
when(editor.putString(anyString(), anyString())).thenReturn(editor);
when(sharedPreferenceEntry.getDateOfBirth()).thenReturn(Calendar.getInstance());
when(editor.putLong(anyString(), anyLong())).thenReturn(editor);
// 测试savePersonalInfo()是否有调用commit
sharedPreferencesHelper.savePersonalInfo(sharedPreferenceEntry);
Mockito.verify(editor).commit();
当然为了简化mock对象的初始化,可以这样写:
(1) 单元测试类定义的开头,添加 @RunWith(MockitoJUnitRunner.class)
注释。此注释可告知 Mockito 测试程序运行的框架;
(2) 在对象字段声明前添加 @Mock
注释。
package com.fanff.unittestdemo.mockdemo;
import android.content.SharedPreferences;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Calendar;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class SharedPreferencesHelperTest
// 如果使用@Mock注解的方式mock对象则需要在类前加 @RunWith(MockitoJUnitRunner.class)
@Mock
SharedPreferences sharedPreferences;
@Mock
SharedPreferenceEntry sharedPreferenceEntry;
@Test
public void testSavePersonalInfo()
SharedPreferencesHelper sharedPreferencesHelper =
new SharedPreferencesHelper(sharedPreferences);
SharedPreferences.Editor editor = Mockito.mock(SharedPreferences.Editor.class);
when(sharedPreferences.edit()).thenReturn(editor);
when(editor.putString(anyString(), anyString())).thenReturn(editor);
when(sharedPreferenceEntry.getDateOfBirth()).thenReturn(Calendar.getInstance());
when(editor.putLong(anyString(), anyLong())).thenReturn(editor);
sharedPreferencesHelper.savePersonalInfo(sharedPreferenceEntry);
Mockito.verify(editor).commit();
@Test
public void testGetPersonalInfo()
// 测试结果及覆盖
三、Mockito方法说明
1. mock对象创建
mock的对象可以通过Mockito.mock()和Mockito.spy()两种方法来创建。
Mock:
* (1) mock对象调用的所有方法都是空方法。非void方法都将返回默认值,比如返回值为int的方法将返回0,返回值为对象的方法将返回null等,而void方法将什么都不做;
* (2) 适用场景:类对外部依赖较多,只关心少数函数的具体实现。Spy:
* (1) 是正常对象的替身,跟正常对象的使用一样;
* (2) 适用场景:类对外部依赖较少,关心大部分函数的具体实现
// 被测代码: Calculator.java
package com.fanff.unittestdemo.junitdemo;
public class Calculator
public int addExact(int x, int y)
return x + y;
public int subtractExact(int x, int y)
return x - y;
public int multiplyExact(int x, int y)
return x * y;
// TODO: zero case
public int intDivide(int x, int y)
return x / y;
// 测试代码:CalculatorMockTest.java
package com.fanff.unittestdemo.mockdemo;
import com.fanff.unittestdemo.junitdemo.Calculator;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
public class CalculatorMockTest
// Mock vs Spy的区别
@Test
public void testSubtractExact()
Calculator calculatorMockObj = Mockito.mock(Calculator.class);
Assert.assertEquals(0, calculatorMockObj.multiplyExact(6, 8));// Pass
// Assert.assertEquals(48, calculatorMockObj.multiplyExact(6, 8));// Fail
Calculator calculatorSpyObj = Mockito.spy(Calculator.class);
Assert.assertEquals(48, calculatorSpyObj.multiplyExact(6, 8));// Pass
// Assert.assertEquals(0, calculatorSpyObj.multiplyExact(6, 8));// Fail
2. Mockito框架中的常见方法说明
大致可以分为两大类: 打桩方法和验证行为。
3. Mockito的局限性
-----------------------------待续--------------------------------
以上是关于Android单元测试系列-Mock之Mockito的主要内容,如果未能解决你的问题,请参考以下文章