Java单元测试——Mock技术

发表于:2020-8-27 09:51

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:顾翔    来源:51Testing软件测试网原创

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

  本文出自51Testing会员投稿,51Testing软件测试网及相关内容提供者拥有内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任。 
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号