1. 程式人生 > >junit使用mock objects進行單元測試

junit使用mock objects進行單元測試

上一篇我介紹了使用stub進行單元測試。那麼mock objects和stub有何區別?什麼情況下使用mock objects呢?

下面摘自junit in action書中的解釋:

mock objects (或者簡稱為 mocks),非常適用於將某一部分程式碼與其他代問隔離開來,並對這部分程式碼進行測試。

mocks 替換了測試中與你的方法協作的物件,從而提供個隔離層。從這一點來講,它與 stub 有些類似。不過相似之處也僅限於

此,因為mocks 並不實現任何邏輯 它們只是提供了一種使測試能夠控制仿造類的所有業務邏輯方法行為的方法的空殼。

 

下面以一個賬戶轉賬的測試用例加以說明。大家可以比較下其與stub的區別。

 

建立賬戶類

package com.lhy.junitkaifa.mocks.account;

/**
 * 賬戶
 *
 * @author xusucheng
 * @create 2018-12-22
 **/
public class Account {
    private String accountId;
    private long balance;

    public Account(String accountId, long balance){
        this.accountId = accountId;
        this.balance = balance;
    }

    public void debit(long amount){
        this.balance-=amount;
    }

    public void credit(long amount){
        this.balance+=amount;
    }

    public long getBalance(){
        return this.balance;
    }
}

建立配置介面與實現

package com.lhy.junitkaifa.mocks.configurations;

/**
 * 配置
 *
 * @author xusucheng
 * @create 2018-12-22
 **/
public interface Configuration {
    String getSQL(String sqlString);
}
package com.lhy.junitkaifa.mocks.configurations;

/**
 * @author xusucheng
 * @create 2018-12-22
 **/
public class DefaultConfiguration implements Configuration {
    public DefaultConfiguration(String configuration){

    }

    @Override
    public String getSQL(String sqlString) {
        return null;
    }
}

 

建立賬戶管理介面與實現

package com.lhy.junitkaifa.mocks.account;

/**
 * 賬戶管理介面
 *
 * @author xusucheng
 * @create 2018-12-22
 **/
public interface AccountManager {
    Account findAccountById(String userId);

    void updateAccount(Account account);
}
package com.lhy.junitkaifa.mocks.account;

import com.lhy.junitkaifa.mocks.configurations.Configuration;
import com.lhy.junitkaifa.mocks.configurations.DefaultConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 賬戶管理介面實現
 *
 * @author xusucheng
 * @create 2018-12-22
 **/
public class AccountManagerImpl implements AccountManager {
    private Log logger;

    private Configuration configuration;

    public AccountManagerImpl(){
        this(LogFactory.getLog(AccountManagerImpl.class),new DefaultConfiguration("technical"));
    }

    public AccountManagerImpl(Log logger, Configuration configuration){
        this.logger = logger;
        this.configuration = configuration;
    }

    @Override
    public Account findAccountById(String userId) {
        this.logger.debug("Getting account for user["+userId+"]");
        this.configuration.getSQL("FIND_ACCOUNT_BY_ID");

        return null;
    }

    @Override
    public void updateAccount(Account account) {
        //Do nothing.
    }


}

 

建立賬戶管理服務類

 

package com.lhy.junitkaifa.mocks.account;

/**
 * 賬戶管理服務
 *
 * @author xusucheng
 * @create 2018-12-22
 **/
public class AccountService {
    private AccountManager accountManager;

    /**
     * 注入具體實現
     * @param accountManager
     */
    public void setAccountManager(AccountManager accountManager){
        this.accountManager = accountManager;
    }

    public void transfer(String fromId, String toId, long amount){
        //轉出賬戶
        Account from = this.accountManager.findAccountById(fromId);
        //轉入賬戶
        Account to = this.accountManager.findAccountById(toId);
        from.debit(amount);
        to.credit(amount);
        this.accountManager.updateAccount(from);
        this.accountManager.updateAccount(to);
    }
}

 

建立測試用賬戶管理介面

package com.lhy.junitkaifa.mocks.account;

import java.util.HashMap;
import java.util.Map;

/**
 * @author xusucheng
 * @create 2018-12-22
 **/
public class MockAccountManager implements AccountManager{
    //儲存所有賬戶
    private Map<String,Account> accounts = new HashMap<>();


    /**
     * 新增賬戶
     * @param userId
     * @param account
     */
    public void addAccount(String userId, Account account){
        this.accounts.put(userId,account);
    }


    /**
     * 獲取賬戶
     * @param userId
     * @return
     */
    @Override
    public Account findAccountById(String userId) {
        return this.accounts.get(userId);
    }

    @Override
    public void updateAccount(Account account) {
        //不幹事
    }
}

建立測試用日誌類

package com.lhy.junitkaifa.mocks.account;

import org.apache.commons.logging.Log;

/**
 * @author xusucheng
 * @create 2018-12-22
 **/
public class MockLog implements Log {
    @Override
    public boolean isFatalEnabled() {
        return false;
    }

    @Override
    public boolean isErrorEnabled() {
        return false;
    }

    @Override
    public boolean isWarnEnabled() {
        return false;
    }

    @Override
    public boolean isInfoEnabled() {
        return false;
    }

    @Override
    public boolean isDebugEnabled() {
        return false;
    }

    @Override
    public boolean isTraceEnabled() {
        return false;
    }

    @Override
    public void fatal(Object o) {

    }

    @Override
    public void fatal(Object o, Throwable throwable) {

    }

    @Override
    public void error(Object o) {

    }

    @Override
    public void error(Object o, Throwable throwable) {

    }

    @Override
    public void warn(Object o) {

    }

    @Override
    public void warn(Object o, Throwable throwable) {

    }

    @Override
    public void info(Object o) {

    }

    @Override
    public void info(Object o, Throwable throwable) {

    }

    @Override
    public void debug(Object o) {

    }

    @Override
    public void debug(Object o, Throwable throwable) {

    }

    @Override
    public void trace(Object o) {

    }

    @Override
    public void trace(Object o, Throwable throwable) {

    }
}

 

建立測試用配置類

package com.lhy.junitkaifa.mocks.configurations;

/**
 * @author xusucheng
 * @create 2018-12-22
 **/
public class MockConfiguration implements Configuration {
    public void setSQL(String sqlString){

    }

    @Override
    public String getSQL(String sqlString) {
        return null;
    }
}

 

建立測試類

package com.lhy.junitkaifa.mocks.account;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

/**
 * @author xusucheng
 * @create 2018-12-22
 **/
public class TestAccountService {
    @Test
    public void testTransferOk(){
        MockAccountManager mockAccountManager = new MockAccountManager();
        Account from = new Account("1",200);
        Account to = new Account("2",100);
        mockAccountManager.addAccount("1", from);
        mockAccountManager.addAccount("2", to);

        AccountService accountService = new AccountService();
        accountService.setAccountManager(mockAccountManager);
        accountService.transfer("1","2",50);

        assertEquals(150,from.getBalance());
        assertEquals(150,to.getBalance());
    }
}

 

執行測試