Use mock object for independent unit test

Source: Internet
Author: User
Use mock object for independent unit test (testing in isolation with mock objects)

An independent test is to test the code in a class or method separately, without testing the code of other classes or methods called in it. That is, it is assumed that all other classes or methods of the call are normally executed.

  • Use mock object
    1. The behavior of the actual object is unknown.
    2. The actual object creation and initialization are very complex.
    3. The actual object has behaviors that are difficult to execute (such as network exceptions ).
    4. The actual object runs very slowly.
    5. The actual object is a user interface program.
    6. The actual object has not been written, and only interfaces are available.
  • Analyze the reason for using mock object

    Suppose we have object A, which frequently calls the method in object B. However, in addition to calling B, some logic Code also exists. At this time, we only want to write a standalone test, instead of testing B (because B may not be written yet, writing only Implemented interfaces or running B too slowly affects our testing efficiency ). In this case, we need to create the mock object of B.

    In other words, we do not care about B now. We assume that B's behavior can run normally. Our goal is to perform a standalone test on a if B runs normally.

    The mock object is the object we don't need to care about first, but our object of interest calls it. Therefore, we prepare a fake product for the object to be followed for use.

  • Example

    Now we have written the class accountservice as follows:

    public class AccountService {         private AccountManager accountManager;         public void setAccountManager(AccountManager manager) {                 this.accountManager = manager;         }         public void transfer(String senderId, String beneficiaryId, long amount) {                 Account sender = this.accountManager.findAccountForUser(senderId);                 Account beneficiary =                         this.accountManager.findAccountForUser(beneficiaryId);                 sender.debit(amount);                 beneficiary.credit(amount);                 this.accountManager.updateAccount(sender);                 this.accountManager.updateAccount(beneficiary);                          } }

    Now we want to test the transfer method, which internally calls two accountmanager methods. But for accountmanager, it is just an interface, as follows:

    public interface AccountManager {         Account findAccountForUser(String userId);         void updateAccount(Account account); }

    So now we need some mockaccountmanager objects. In addition, the method body is very simple, That is, assuming that it returns a certain value.

    We also have the account class here.

    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;         }           public String getAccountId() {                 return accountId;         }   } 

    The account class here is so simple that when we test the accountservice, the mock objects that do not create an account are the same. Why don't we use real object testing. In this case, we can think back to the scenarios where we use mock objects.

    The following is a test of the accountservice's transfer method.

    public class AccountService1Tests extends TestCase {         public void testTransfer(){                          AccountService as = new AccountService();                 MockAccountManager mockAccountManager = new MockAccountManager();                 Account accountA = new Account("A",3000);                 Account accountB = new Account("B",2000);                                  mockAccountManager.addAccount(accountA);                 mockAccountManager.addAccount(accountB);                                  as.setAccountManager(mockAccountManager);                          as.transfer("A","B",1005);                                  assertEquals(accountA.getBalance(),1995);                 assertEquals(accountB.getBalance(),3005);                  } }

    Here, we have completed the test of the transfer method, assuming that the accountmanager method works normally.

  • Dynamic mock object (easymock and jmock)

    Both easymock and jmock are open source, the former is in SourceForge, and the latter is in codehaus. For these OSS applications, you do not need to manually create a mock object.

    1. Easymock

      Now we still need to test the accountservice's transfer method. We have written the accountservice2tests class.

      Public class accountservice2tests extends testcase {public void testtransfer () {// setup // create a mockcontrol object and associate it with accountmanager mockcontrol control = mockcontrol. createcontrol (accountmanager. class); // get a running mock object accountmanager mockaccountmanager = (accountmanager) control. getmock (); accountservice as = new accountservice ();. setaccountmanager (mockaccountmanager); // configure CT/* set the mock object behavior */accoun T accounta = new account ("A", 3000); account accountb = new account ("B", 2000 ); // set the execution method findaccountforuser ("A") in the running state and let it return the accounta object. Mockaccountmanager. findaccountforuser ("A"); control. setreturnvalue (accounta); // sets the execution method findaccountforuser ("B") in the running state and returns the accountb object. Mockaccountmanager. findaccountforuser ("B"); control. setreturnvalue (accountb); // sets the execution method updateaccount (accounta) in the running state ). Mockaccountmanager. updateaccount (accounta); mockaccountmanager. updateaccount (accountb);/* run the test with mock object */control. replay ();. transfer ("A", "B", 1005); assertequals (accounta. getbalance (), 1995); assertequals (accountb. getbalance (), 3005); control. verify ();}}

      Here we do not use the mockaccountmanager object, but the dynamic mock object created with easymock. So we don't need to write mock objects manually.

    2. Jmock

      The following is a test of the accountservice3tests standalone of the transfer method of accountservice written with jmock.

      public class AccountService3Tests extends MockObjectTestCase {                  public void testTransfer(){                 Mock mock = new Mock(AccountManager.class);                 AccountManager mockAccountManager =(AccountManager)mock.proxy();                 AccountService as = new AccountService();                 as.setAccountManager(mockAccountManager);                 Account accountA = new Account("A",3000);                  Account accountB = new Account("B",2000);                 // expectations                 mock.expects(once()).method("findAccountForUser").with(same("A")).will(returnValue(accountA));                 mock.expects(once()).method("findAccountForUser").with(same("B")).will(returnValue(accountB));                 mock.expects(once()).method("updateAccount").with(same(accountA)).isVoid();                  mock.expects(once()).method("updateAccount").with(same(accountB)).isVoid();                                  //excute                 as.transfer("A","B",1005);                                  assertEquals(accountA.getBalance() , 1995);                 assertEquals(accountB.getBalance() , 3005);                                  verify();         } } 

      From the test above, we can see that when using jmock for testing, mockobjecttestcase must be inherited. Because once, same, returnvalue, and other methods are used. Others are basically similar to easymock, but jmock is easier to understand.

    From: http://blog.csdn.net/sunfmin/archive/2004/11/23/192365.aspx

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.