lsekfe 发表于 2020-12-7 10:41:38

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]
查看完整版本: Java单元测试——Mock技术