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());
    }
}

 

运行测试

 

 

 

 

posted @   一锤子技术员  阅读(8)  评论(0编辑  收藏  举报  
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示