mock测试_Java单元测试——Mock技术配置

1. 源代码

AccountService.javapackage com.account;import com.account.Account;import com.account.AccountManager;public class AccountService{  //使用的帐户管理器实现    private AccountManager accountManager;    //设置帐户管理器实现的设置方法    public void setAccountManager( AccountManager manager ){        this.accountManager = manager;    }    //一个设置客户经理实现从账户到账户的senderId beneficiaryId setter方法。    //senderId:转出方Id    //beneficiaryId:收益方Id    //amount:金额    public void transfer( String senderId, String beneficiaryId, long amount ){        //初始化转出方与收益方,findAccountForUser为接口类方法      Account sender = this.accountManager.findAccountForUser( senderId );        Account beneficiary = this.accountManager.findAccountForUser( beneficiaryId );        //转入和收益        sender.debit( amount );        beneficiary.credit( amount );        //更新,updateAccount为接口类方法        this.accountManager.updateAccount( sender );        this.accountManager.updateAccount( beneficiary );    }}

Account.java

package com.account;public class Account{    private String accountId;    private long balance;    public Account(String accountId, long initialBalance){        this.accountId = accountId;        this.balance = initialBalance;    }    //借记    public void debit( long amount ){        this.balance -= amount;    }    //信用    public void credit( long amount ){        this.balance += amount;    }    public long getBalance(){        return this.balance;    }}

AccountManager.java

package com.account;import com.account.Account;public interface AccountManager{    Account findAccountForUser(String userId );    void updateAccount(Account account );    }

由于在这里AccountManager.java仅仅做了一个interface,我们主要Mock的是这个类。这几个类的类关系图如下:

c52e5c9312e0ca5e3a2ca03f8f3a9134.png

通常的调用方法如下:

@Test  public void testTransferOK() {    Account sendAccount = new Account("1",200);     Account beneficiaryAccount = new Account("2",100);    AccountManager. updateAccount( senderAccount );    AccountManager.updateAccount( beneficiaryAccount );    AccountManager.findAccountForUser("1" )     AccountManager.findAccountForUser( "2" )     AccountService accountService = new AccountService();     accountService.setAccountManager(AccountManager);     accountService.transfer("1","2",50); //转钱            Assertions.assertEquals(150,sendAccount.getBalance());     Assertions.assertEquals(150,beneficiaryAccount.getBalance());  }

2. 最通用的Mock技术

StubAccountManager.javapackage com.account;import java.util.HashMap;public class StubAccountManager implements AccountManager{  private HashMap accounts = new HashMap();  public void addAcount(String userId,Account account){    this.accounts.put(userId,account);  }    public Account findAccountForUser(String userId){    return this.accounts.get(userId);  }    public void updateAccount(Account account){    //do nothing  }}

Account.java

import static org.junit.Assert.assertEquals;import org.junit.jupiter.api.Test;public class TestAccountService {  @Test  public void testTransferOK() {    StubAccountManager stubAccountManager = new StubAccountManager(); //定义MockAccountManager类    Account sendAccount = new Account("1",200); //定义收钱方和出钱方两个Account    Account beneficiaryAccount = new Account("2",100);    stubAccountManager.addAcount("1", sendAccount); //初始化收钱方和出钱方HashMap    stubAccountManager.addAcount("2", beneficiaryAccount);    AccountService accountService = new AccountService(); //初始化AccountService类    accountService.setAccountManager(stubAccountManager); //初始化AccountManager    accountService.transfer("1","2",50); //转钱            Assertions.assertEquals(150,sendAccount.getBalance()); //判断转换后收付方金额是否正确    Assertions.assertEquals(150,beneficiaryAccount.getBalance());  }}

3.EasyMock技术

EasyMock需要以下两个jar包:easymock-2.4.jar和easymockclassextension-2.4.jar

TestAccountServiceEasyMock.java

package com.account;import static org.easymock.EasyMock.createMock;import static org.easymock.EasyMock.replay;import static org.easymock.EasyMock.expect;import static org.easymock.EasyMock.verify;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.AfterEach;import org.junit.jupiter.api.Assertions;import org.junit.jupiter.api.DisplayName;import org.junit.jupiter.api.Test;import com.account.Account;import com.account.AccountManager;import com.account.AccountService;public class TestAccountServiceEasyMock {  private AccountManager mockAccountManager;    @BeforeEach    public void setUp(){        //初始化easyMock      mockAccountManager = createMock("mockAccountManager", AccountManager.class );    }    @Test    @DisplayName("测试转账")    public void testTransferOk(){        Account senderAccount = new Account( "1", 200 );        Account beneficiaryAccount = new Account( "2", 100 );                //开始定义期望        mockAccountManager.updateAccount( senderAccount );        mockAccountManager.updateAccount( beneficiaryAccount );        //EasyMock的expect和replay方法        expect( mockAccountManager.findAccountForUser( "1" ) ).andReturn( senderAccount ); //期望返回senderAccount        expect( mockAccountManager.findAccountForUser( "2" ) ).andReturn( beneficiaryAccount ); //期望返beneficiaryAccount        replay( mockAccountManager );//切换到replay状态 Record-> replay,在replay状态才可以进行验证        AccountService accountService = new AccountService();        accountService.setAccountManager( mockAccountManager );        accountService.transfer( "1", "2", 50 );        Assertions.assertEquals( 150, senderAccount.getBalance() );        Assertions.assertEquals( 150, beneficiaryAccount.getBalance() );    }    @AfterEach    public void tearDown(){        verify( mockAccountManager );    }}

4. JMock技术

JMock依赖下面11个jar包。另外JMock不完全兼容JUnit5

18df29409b6f8998484ff32e5365cff5.png

TestAccountServiceJMock.java

package com.account;import org.jmock.integration.junit4.JMock;import org.jmock.integration.junit4.JUnit4Mockery;import org.jmock.Expectations;import org.jmock.Mockery;import org.junit.jupiter.api.Assertions;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.DisplayName;import org.junit.jupiter.api.Test;import org.junit.runner.RunWith;import com.account.Account;import com.account.AccountManager;import com.account.AccountService;@RunWith(JMock.class)public class TestAccountServiceJMock {  /**     * The mockery context that we use to create our mocks.     */    private Mockery context = new JUnit4Mockery();    /**     * The mock instance of the AccountManager to use.     */    private AccountManager mockAccountManager;  @BeforeEach  public void setUp(){     mockAccountManager = context.mock( AccountManager.class );  }  @Test  @DisplayName("测试转账")    public void testTransferOk()    {        final Account senderAccount = new Account( "1", 200 );        final Account beneficiaryAccount = new Account( "2", 100 );        context.checking( new Expectations()        {            {                oneOf( mockAccountManager ).findAccountForUser( "1" );                will( returnValue( senderAccount ) );                oneOf( mockAccountManager ).findAccountForUser( "2" );                will( returnValue( beneficiaryAccount ) );                oneOf( mockAccountManager ).updateAccount( senderAccount );                oneOf( mockAccountManager ).updateAccount( beneficiaryAccount );            }        } );        AccountService accountService = new AccountService();        accountService.setAccountManager( mockAccountManager );        accountService.transfer( "1", "2", 50 );        Assertions.assertEquals( 150, senderAccount.getBalance() );        Assertions.assertEquals( 150, beneficiaryAccount.getBalance() );    }  }

4.1 One,one of

JMock2.4版以前:one;

JMock2.51版以后:one of。

  • oneOf (anObject).doSomething(); will(returnValue(10));

  • oneOf (anObject).doSomething(); will(returnValue(20));

  • oneOf (anObject).doSomething(); will(returnValue(30));

第一次调用时会返回10,第二次会返回20,第三次会返回30.

4.2 atLeast(n).of

atLeast(1).of (anObject).doSomething();  

will(onConsecutiveCalls( returnValue(10),  returnValue(20),  returnValue(30)));

这里atLeast (1)表明doSomething方法将至少被调用一次,但不超过3次。且调用的返回值分别是10、20、30.

语句

含义

one (one of)

调用应该是一次且仅一次。

exactly(times).of

调用应该正好是n次。注:one(one of)是exactly(1) 速写。

atLeast(times).of

至少需要调用n次

atMost(times).of

调用最多应为n次。

between(min, max).of

调用至少应为min次,最多为max次。

allowing

允许调用任意次数,但不必发生。

ignoring

和allowing一样。应选择允许或忽略,以使测试代码清楚地表达意图。

never

根本不需要调用。这是用来使测试更加明确,从而更容易理解。

5. mockito技术

需要mockito-all-1.9.5.jar包。

package com.account;import static org.mockito.Mockito.*;import org.junit.jupiter.api.Assertions;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.DisplayName;import org.junit.jupiter.api.Test;import org.mockito.Mockito;import com.account.Account;import com.account.AccountManager;import com.account.AccountService;public class TestAccountServiceMockito {  private AccountManager mockAccountManager;  private Account senderAccount;  private Account beneficiaryAccount;  @BeforeEach  public void setUp(){    mockAccountManager = Mockito.mock(AccountManager.class);        senderAccount = new Account( "1", 200 );        beneficiaryAccount = new Account( "2", 100 );                mockAccountManager.updateAccount( senderAccount );        mockAccountManager.updateAccount( beneficiaryAccount );                when(mockAccountManager.findAccountForUser("1")).thenReturn( senderAccount );        when(mockAccountManager.findAccountForUser("2")).thenReturn( beneficiaryAccount );  }    @Test  @DisplayName("测试转账")  public void test() {        AccountService accountService = new AccountService();        accountService.setAccountManager( mockAccountManager );        accountService.transfer( "1", "2", 50 );        Assertions.assertEquals( 150, senderAccount.getBalance() );        Assertions.assertEquals( 150, beneficiaryAccount.getBalance() );  }}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值