Java单元测试——Mock技术
1.源代码AccountService.java
package 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的是这个类。这几个类的类关系图如下:
通常的调用方法如下:
@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.java
package com.account;
import java.util.HashMap;
public class StubAccountManager implements AccountManager{
private HashMap<String,Account> accounts = new HashMap<String,Account>();
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
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.
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() );
}
}
页:
[1]