51Testing软件测试论坛

标题: Java单元测试——Mock技术 [打印本页]

作者: lsekfe    时间: 2020-12-7 10:41
标题: Java单元测试——Mock技术
1.源代码
  AccountService.java
  1.  package com.account;

  2.   import com.account.Account;

  3.   import com.account.AccountManager;

  4.   public class AccountService

  5.   {

  6.   //使用的帐户管理器实现

  7.       private AccountManager accountManager;

  8.       //设置帐户管理器实现的设置方法

  9.       public void setAccountManager( AccountManager manager )

  10.       {

  11.           this.accountManager = manager;

  12.       }

  13.       //一个设置客户经理实现从账户到账户的senderId beneficiaryId setter方法。

  14.       //senderId:转出方Id

  15.       //beneficiaryId:收益方Id

  16.       //amount:金额

  17.       public void transfer( String senderId, String beneficiaryId, long amount )

  18.       {

  19.           //初始化转出方与收益方,findAccountForUser为接口类方法

  20.       Account sender = this.accountManager.findAccountForUser( senderId );

  21.           Account beneficiary = this.accountManager.findAccountForUser( beneficiaryId );

  22.           //转入和收益

  23.           sender.debit( amount );

  24.           beneficiary.credit( amount );

  25.           //更新,updateAccount为接口类方法

  26.           this.accountManager.updateAccount( sender );

  27.           this.accountManager.updateAccount( beneficiary );

  28.       }

  29.   }
复制代码
Account.java
  1.  package com.account;

  2.   public class Account

  3.   {

  4.       private String accountId;

  5.       private long balance;

  6.       public Account(String accountId, long initialBalance)

  7.       {

  8.           this.accountId = accountId;

  9.           this.balance = initialBalance;

  10.       }

  11.       //借记

  12.       public void debit( long amount )

  13.       {

  14.           this.balance -= amount;

  15.       }

  16.       //信用

  17.       public void credit( long amount )

  18.       {

  19.           this.balance += amount;

  20.       }

  21.       public long getBalance()

  22.       {

  23.           return this.balance;

  24.       }

  25.   }
复制代码
AccountManager.java
  1.  package com.account;

  2.   import com.account.Account;

  3.   public interface AccountManager

  4.   {

  5.       Account findAccountForUser(String userId );

  6.       void updateAccount(Account account );   

  7.   }
复制代码
由于在这里AccountManager.java仅仅做了一个interface,我们主要Mock的是这个类。这几个类的类关系图如下:
[attach]131172[/attach]
 通常的调用方法如下:
  1. @Test

  2.   public void testTransferOK() {

  3.   Account sendAccount = new Account("1",200);

  4.   Account beneficiaryAccount = new Account("2",100);

  5.   AccountManager. updateAccount( senderAccount );

  6.   AccountManager.updateAccount( beneficiaryAccount );

  7.   AccountManager.findAccountForUser("1" )

  8.   AccountManager.findAccountForUser( "2" )

  9.   AccountService accountService = new AccountService();

  10.   accountService.setAccountManager(AccountManager);

  11.   accountService.transfer("1","2",50); //转钱

  12.   Assertions.assertEquals(150,sendAccount.getBalance());

  13.   Assertions.assertEquals(150,beneficiaryAccount.getBalance());

  14.   }
复制代码
2.最通用的Mock技术  StubAccountManager.java
  1. package com.account;

  2.   import java.util.HashMap;

  3.   public class StubAccountManager implements AccountManager{

  4.   private HashMap<String,Account> accounts = new HashMap<String,Account>();

  5.   public void addAcount(String userId,Account account){

  6.   this.accounts.put(userId,account);

  7.   }

  8.   

  9.   public Account findAccountForUser(String userId){

  10.   return this.accounts.get(userId);

  11.   }

  12.   

  13.   public void updateAccount(Account account){

  14.   //do nothing

  15.   }

  16.   }
复制代码
Account.java
  1. import static org.junit.Assert.assertEquals;

  2.   import org.junit.jupiter.api.Test;

  3.   public class TestAccountService {

  4.   @Test

  5.   public void testTransferOK() {

  6.   StubAccountManager stubAccountManager = new StubAccountManager(); //定义MockAccountManager类

  7.   Account sendAccount = new Account("1",200); //定义收钱方和出钱方两个Account

  8.   Account beneficiaryAccount = new Account("2",100);

  9.   stubAccountManager.addAcount("1", sendAccount); //初始化收钱方和出钱方HashMap

  10.   stubAccountManager.addAcount("2", beneficiaryAccount);

  11.   AccountService accountService = new AccountService(); //初始化AccountService类

  12.   accountService.setAccountManager(stubAccountManager); //初始化AccountManager

  13.   accountService.transfer("1","2",50); //转钱

  14.   Assertions.assertEquals(150,sendAccount.getBalance()); //判断转换后收付方金额是否正确

  15.   Assertions.assertEquals(150,beneficiaryAccount.getBalance());

  16.   }}
复制代码
3.EasyMock技术  EasyMock需要以下两个jar包:easymock-2.4.jar和easymockclassextension-2.4.jar
  TestAccountServiceEasyMock.java
  1. package com.account;

  2.   import static org.easymock.EasyMock.createMock;

  3.   import static org.easymock.EasyMock.replay;

  4.   import static org.easymock.EasyMock.expect;

  5.   import static org.easymock.EasyMock.verify;

  6.   import org.junit.jupiter.api.BeforeEach;

  7.   import org.junit.jupiter.api.AfterEach;

  8.   import org.junit.jupiter.api.Assertions;

  9.   import org.junit.jupiter.api.DisplayName;

  10.   import org.junit.jupiter.api.Test;

  11.   import com.account.Account;

  12.   import com.account.AccountManager;

  13.   import com.account.AccountService;

  14.   public class TestAccountServiceEasyMock {

  15.   private AccountManager mockAccountManager;

  16.       @BeforeEach

  17.       public void setUp()

  18.       {

  19.           //初始化easyMock

  20.       mockAccountManager = createMock("mockAccountManager", AccountManager.class );

  21.       }

  22.       @Test

  23.       @DisplayName("测试转账")

  24.       public void testTransferOk()

  25.       {

  26.           Account senderAccount = new Account( "1", 200 );

  27.           Account beneficiaryAccount = new Account( "2", 100 );

  28.           

  29.           //开始定义期望

  30.           mockAccountManager.updateAccount( senderAccount );

  31.           mockAccountManager.updateAccount( beneficiaryAccount );

  32.           //EasyMock的expect和replay方法

  33.           expect( mockAccountManager.findAccountForUser( "1" ) ).andReturn( senderAccount ); //期望返回senderAccount

  34.           expect( mockAccountManager.findAccountForUser( "2" ) ).andReturn( beneficiaryAccount ); //期望返beneficiaryAccount

  35.           replay( mockAccountManager );//切换到replay状态 Record-> replay,在replay状态才可以进行验证

  36.           AccountService accountService = new AccountService();

  37.           accountService.setAccountManager( mockAccountManager );

  38.           accountService.transfer( "1", "2", 50 );

  39.           Assertions.assertEquals( 150, senderAccount.getBalance() );

  40.           Assertions.assertEquals( 150, beneficiaryAccount.getBalance() );

  41.       }

  42.       @AfterEach

  43.       public void tearDown()

  44.       {

  45.           verify( mockAccountManager );

  46.       }

  47.   }
复制代码
4. JMock技术  JMock依赖下面11个jar包。另外JMock不完全兼容JUnit5
[attach]131173[/attach]
 TestAccountServiceJMock.java
  1. package com.account;

  2.   import org.jmock.integration.junit4.JMock;

  3.   import org.jmock.integration.junit4.JUnit4Mockery;

  4.   import org.jmock.Expectations;

  5.   import org.jmock.Mockery;

  6.   import org.junit.jupiter.api.Assertions;

  7.   import org.junit.jupiter.api.BeforeEach;

  8.   import org.junit.jupiter.api.DisplayName;

  9.   import org.junit.jupiter.api.Test;

  10.   import org.junit.runner.RunWith;

  11.   import com.account.Account;

  12.   import com.account.AccountManager;

  13.   import com.account.AccountService;

  14.   @RunWith(JMock.class)

  15.   public class TestAccountServiceJMock {

  16.   /**

  17.        * The mockery context that we use to create our mocks.

  18.        */

  19.       private Mockery context = new JUnit4Mockery();

  20.       /**

  21.        * The mock instance of the AccountManager to use.

  22.        */

  23.       private AccountManager mockAccountManager;

  24.   @BeforeEach

  25.   public void setUp(){

  26.    mockAccountManager = context.mock( AccountManager.class );

  27.   }

  28.   @Test

  29.   @DisplayName("测试转账")

  30.       public void testTransferOk()

  31.       {

  32.           final Account senderAccount = new Account( "1", 200 );

  33.           final Account beneficiaryAccount = new Account( "2", 100 );

  34.           context.checking( new Expectations()

  35.           {

  36.               {

  37.                   oneOf( mockAccountManager ).findAccountForUser( "1" );

  38.                   will( returnValue( senderAccount ) );

  39.                   oneOf( mockAccountManager ).findAccountForUser( "2" );

  40.                   will( returnValue( beneficiaryAccount ) );

  41.                   oneOf( mockAccountManager ).updateAccount( senderAccount );

  42.                   oneOf( mockAccountManager ).updateAccount( beneficiaryAccount );

  43.               }

  44.           } );

  45.           AccountService accountService = new AccountService();

  46.           accountService.setAccountManager( mockAccountManager );

  47.           accountService.transfer( "1", "2", 50 );

  48.           Assertions.assertEquals( 150, senderAccount.getBalance() );

  49.           Assertions.assertEquals( 150, beneficiaryAccount.getBalance() );

  50.       }  

  51.   }
复制代码
4.1 One,one of  JMock2.4版以前:one;
  JMock2.51版以后:one of。
  1. oneOf (anObject).doSomething(); will(returnValue(10));

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

  3.   oneOf (anObject).doSomething(); will(returnValue(30));
复制代码
 第一次调用时会返回10,第二次会返回20,第三次会返回30。  4.2 atLeast(n).of
  1.  atLeast(1).of (anObject).doSomething();  

  2.   will(onConsecutiveCalls( returnValue(10),  returnValue(20),  returnValue(30)));
复制代码
 这里atLeast (1)表明doSomething方法将至少被调用一次,但不超过3次。且调用的返回值分别是10、20、30.
[attach]131174[/attach]
5. mockito技术  需要mockito-all-1.9.5.jar包。
  1.  package com.account;

  2.   import static org.mockito.Mockito.*;

  3.   import org.junit.jupiter.api.Assertions;

  4.   import org.junit.jupiter.api.BeforeEach;

  5.   import org.junit.jupiter.api.DisplayName;

  6.   import org.junit.jupiter.api.Test;

  7.   import org.mockito.Mockito;

  8.   import com.account.Account;

  9.   import com.account.AccountManager;

  10.   import com.account.AccountService;

  11.   public class TestAccountServiceMockito {

  12.   private AccountManager mockAccountManager;

  13.   private Account senderAccount;

  14.   private Account beneficiaryAccount;

  15.   @BeforeEach

  16.   public void setUp(){

  17.   mockAccountManager = Mockito.mock(AccountManager.class);

  18.   

  19.   senderAccount = new Account( "1", 200 );

  20.           beneficiaryAccount = new Account( "2", 100 );

  21.           

  22.           mockAccountManager.updateAccount( senderAccount );

  23.           mockAccountManager.updateAccount( beneficiaryAccount );

  24.           

  25.           when(mockAccountManager.findAccountForUser("1")).thenReturn( senderAccount );

  26.           when(mockAccountManager.findAccountForUser("2")).thenReturn( beneficiaryAccount );

  27.   }

  28.   

  29.   @Test

  30.   @DisplayName("测试转账")

  31.   public void test() {

  32.           AccountService accountService = new AccountService();

  33.           accountService.setAccountManager( mockAccountManager );

  34.           accountService.transfer( "1", "2", 50 );

  35.           Assertions.assertEquals( 150, senderAccount.getBalance() );

  36.           Assertions.assertEquals( 150, beneficiaryAccount.getBalance() );

  37.   }

  38.   }
复制代码






















欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2