EasyMock use method and principle analysis _easymock

Source: Internet
Author: User
Tags instance method throw exception throwable

A mock method is a common technique in unit testing, and its main function is to simulate objects that are not easily constructed or complex in the application, thus isolating the test from objects outside the test boundary.

Writing a custom Mock object requires additional coding and may also introduce errors. EasyMock provides a way to dynamically build mock objects based on the specified interface, avoiding the manual scripting of mock objects. This article will show you how to use EasyMock for unit testing and analyze the principles of EasyMock. 1. Mock objects and EasyMock introduction unit tests and Mock methods

Unit testing is the validation of the functionality of one of the modules in the application. In the unit test, we often encounter the problem that the other collaborative modules in the application have not yet been developed, or the test module needs to interact with some objects that are not easy to construct and more complex. In addition, because we cannot be sure of the correctness of the other modules, we are not sure which module caused the problem found in the test.

Mock objects can simulate the behavior of other collaborative modules, and the test module will be able to obtain an isolated test environment by collaborating with mock objects. In addition, mock objects can simulate an application that is not easy to construct (such as HttpServletRequest must be constructed in a Servlet container) and more complex objects (such as the ResultSet object in JDBC) to make the test work smoothly. EasyMock Introduction

The manual construction of mock objects creates additional coding for developers, and the code written to create mock objects is likely to introduce errors. Currently, there are many open source projects that support dynamic building of Mock objects that can be dynamically generated from existing interfaces or classes, not only to avoid additional coding efforts but also to reduce the likelihood of introducing errors.

EasyMock is a set of class libraries used to generate Mock objects for a given interface in a simple way. It provides a simulation of the interface, the ability to record, replay, check three steps to complete the general test process, you can verify the method call type, number of times, order, you can make Mock object return the specified value or throw the specified exception. With EasyMock, we can easily construct Mock objects to make unit tests go smoothly. Install EasyMock

EasyMock is an open source project using MIT license, where you can download the relevant zip file from Sourceforge. The latest version of the EasyMock you can download today is 2.3, and it needs to run on the Java 5.0 platform. If your application is running on a Java 1.3 or 1.4 platform, you can choose EasyMock1.2. After you extract the zip package, you can find the Easymock.jar file. If you are using Eclipse as the IDE, add Easymock.jar to the libraries of your project (as shown in the following illustration). In addition, because our test cases run in a JUnit environment, you also need Junit.jar (version 3.8.1 above). Figure 1:eclipse Libraries in the project

Back to the top 2. Using EasyMock for unit testing

With EasyMock, we can dynamically create mock objects for the specified interface and use mock objects to simulate collaborative modules or domain objects, thus making unit tests work smoothly. This process can be roughly divided into the following steps: Using EasyMock to generate mock objects, setting the expected behavior and output of mock objects, switching mock objects to replay states, invoking mock object methods for unit testing, and verifying the behavior of mock objects Certificate

Next, we'll take a few steps to illustrate each of these. In addition to the basic steps above, EasyMock also provides support for features such as special Mock object types, specific parameter matching methods, which we will explain later in this chapter. Using EasyMock to generate Mock objects

EasyMock can dynamically create mock objects based on the specified interface or class (EasyMock only supports generating mock objects for the interface, if you need to generate mock objects for the class, and expansion packs are available on the EasyMock's home page), we ResultSet Interface as an example to illustrate the functionality of Easymock. Java.sql.ResultSet is an interface that every Java developer is familiar with: listing 1:resultset interfaces

Public interface Java.sql.ResultSet {
...
Public abstract java.lang.String getString (int arg0) throws java.sql.SQLException;
public abstract double getdouble (int arg0) throws java.sql.SQLException;
......
}

In general, building a real RecordSet object requires a complex process: during development, developers typically write a dbutility class to get the database connection Connection and create a Statement using Connection. Executes a Statement to get one or more ResultSet objects. Such a construction process is complex and relies on the proper operation of the database. A problem with a database or database interaction module can affect the results of a unit test.

We can solve this problem by using EasyMock to dynamically build Mock objects of the ResultSet interface. Some simple test cases require only a mock object, at which point we can create mock objects in the following ways:

ResultSet Mockresultset = Createmock (Resultset.class);

Where Createmock is a static method provided by the Org.easymock.EasyMock class, you can introduce it through the static import (note: Static import is the new feature provided by Java 5.0).

If you need to use more than one mock object in a relatively complex test case, EasyMock provides another mechanism for generating and managing mock objects:

Imockscontrol control = Easymock.createcontrol ();
Java.sql.Connection mockconnection = Control.createmock (connection.class);
Java.sql.Statement mockstatement = Control.createmock (statement.class);
Java.sql.ResultSet Mockresultset = Control.createmock (Resultset.class);

The CreateControl method of the EasyMock class creates an interface-Imockscontrol object that can create and manage multiple Mock objects. If you need to use multiple mock objects in your tests, we recommend that you use this mechanism because it provides a relatively convenient way to manage multiple mock objects.

If you are simulating a specific class instead of an interface, you will need to download the expansion pack EasyMock class Extension 2.2.2. When you simulate a specific class, you can simply replace the static method in the Org.easymock.EasyMock class with a static method in the Org.easymock.classextension.EasyMock class. Set the expected behavior and output of Mock objects

During a complete testing process, a Mock object will experience two states: the record state and the replay state. Once a Mock object is created, its state is placed as a record. In the record state, the user can set the expected behavior and output of the mock object, which is recorded and stored in a mock object.

The process of adding mock object behavior can usually be divided into 3 steps: Invoking a particular method of a mock object, and Expectlastcall obtaining the corresponding iexpectation of the previous method call through the static method provided by Org.easymock.EasyMock Setters instance; Sets the expected output of the Mock object through the Iexpectationsetters instance.

Set expected return value

The behavior of mock objects can be simply understood as the output generated by the invocation of mock object methods and by method invocations. In EasyMock 2.3, the addition and setting of Mock object behavior is implemented through interface iexpectationsetters. A Mock object method invocation can produce two types of output: (1) produce a return value, (2) throw an exception. The interface Iexpectationsetters provides a variety of methods for setting the expected output, where the Andreturn method is corresponding to the set return value:

Iexpectationsetters<t> Andreturn (T value);

We still use Mock objects for the ResultSet interface as an example, and if you want the return value of method mockresult.getstring (1) to be "My returns", you can use the following statement:

Mockresultset.getstring (1);
Expectlastcall (). Andreturn ("I return value");

The above statement indicates that the Mockresultset getString method is invoked once, and that the return value of this call is "my returns". Sometimes we want the call of a method to always return the same value, and to avoid having to set the behavior of the Mock object once for each invocation, we can use the method of setting the default return value:

void Andstubreturn (Object value);

Let's say we created Mock objects Mockstatement and Mockresultset for the Statement and ResultSet interfaces, and during the test we wanted the Mockstatement method of the ExecuteQuery object to always return Mockresultset, we can use the following statement

Mockstatement.executequery ("SELECT * from sales_order_table");
Expectlastcall (). Andstubreturn (Mockresultset);

EasyMock the Object.Equals () method is used by default when matching parameter values. Therefore, if we use the "select * from Sales_order_table" as a parameter, the expected method will not be invoked. If you want the SQL statements in the previous example to be case-insensitive, you can solve the problem with a special parameter match, which we'll explain in the chapter "using the parameter matching in EasyMock."

Set expected exception throw

The expected output of an object's behavior may be an exception, in addition to the return value. Iexpectationsetters provides a way to set the expected throw exception:

Iexpectationsetters<t> Andthrow (Throwable throwable);

Similar to setting the default return value, the Iexpectationsetters interface also provides a function to set the default exception to be thrown:

void Andstubthrow (Throwable throwable);

Set the number of expected method calls

With the above function, you can set the expected output of a Mock object's specific behavior. In addition to setting the expected output, the Iexpectationsetters interface allows the user to limit the number of times a method is invoked. One of the commonly used methods in Iexpectationsetters is the Times method:

Iexpectationsetters<t>times (int count);

This method can be used to Mock the number of calls made by an object method. Suppose we want the Mockresultset getString method to be called 3 times during the test, and the return value for the period is "my", we can use the following statement:

Mockresultset.getstring (1);
Expectlastcall (). Andreturn ("I return value"). Times (3);


Note that the return value of the Andreturn and Andthrow methods remains a iexpectationsetters instance, so we can continue to invoke the Times method on this basis.

In addition to setting the number of calls that are determined, Iexpectationsetters also provides several other ways to set the number of inaccurate calls:
Times (int mintimes, int maxtimes): This method is called Mintimes at least, and is called maxtimes times.
Atleastonce (): The method is called at least once.
Anytimes (): This method can be invoked any time.

The return value type of some methods is void, for which we do not need to set the return value, as long as the number of calls is set. Take the Close method of the ResultSet interface as an example, assuming that the method is invoked 3 to 5 times during the test:

Mockresultset.close ();
Expectlastcall (). Times (3, 5);

To simplify writing, EasyMock also provides another statement pattern that sets the behavior of a Mock object. For the previous example, you can also write it as:

Expect (Mockresult.close ()). Times (3, 5);


This statement is exactly the same as the statement functionality in the previous example. To switch a Mock object to a replay state

In both stages of generating mock objects and setting mock object behavior, the mock object's state is a record. At this stage, the Mock object records the user's preferences for expected behavior and output.

Before you actually test with a mock object, we need to switch the state of the mock object to replay. In the replay state, a Mock object can make the expected response to a specific method invocation based on the setting. There are two ways to switch a mock object to a replay state, and you need to choose from the way a mock object is generated. If the mock object is generated by the static method Createmock provided by the Org.easymock.EasyMock class (the first Mock object generation method described in section 1th), then the Easymock class provides a corresponding replay method for using the mock Object switch to Replay state:

Replay (Mockresultset);

If the mock object is generated by the Createmock method provided by the Imockscontrol interface (the second Mock object generation method described in section 1th), you can still switch through the Imockscontrol interface for all mock objects that it creates:

Control.replay ();

The above statement switches to the replay state for 3 Mock objects, such as Mockconnection, Mockstatement, and Mockresultset, which are generated in section 1th. Calling Mock object methods for unit testing

To better illustrate the functionality of EasyMock, we introduce the example in Src.zip to explain the role of Mock objects in the actual testing phase. All of the sample code can be found in Src.zip. If you are using the IDE as Eclipse, you can see the additional project in Workspace (shown in the following illustration) after you import src.zip. Figure 2: Workspace after import of Src.zip

The following is an interface SalesOrder in the example code whose main function is to read the Region and total price of a sales order from the database, and to calculate the Salesorderimpl Price level (complete implementation code can be found in Src.zip): Listing 2:salesorder interface

Public interface SalesOrder
{
  ...
  public void Loaddatafromdb (ResultSet ResultSet) throws SQLException;	
  Public String getpricelevel ();
}

The implementation of the Loaddatafromdb in its implementation class Salesorderimpl is as follows: listing 3:SALESORDERIMPL implementation

public class Salesorderimpl implements SalesOrder
{
  ...
  public void Loaddatafromdb (ResultSet ResultSet) throws SQLException
  {
    ordernumber = resultset.getstring (1);
    Region = resultset.getstring (2);
    Totalprice = resultset.getdouble (3);
  }
  ......
}

Method Loaddatafromdb read the data contained by the ResultSet object. When we adjust the previously defined mock object to the replay state and pass the object as a parameter, the mock object's method returns the predefined expected return value. The complete TestCase is as follows: Listing 4: Complete TestCase

public class Salesordertestcase extends TestCase {public void Testsalesorder () {Imockscontrol control = easymock.c
    Reatecontrol ();
    ......
    ResultSet Mockresultset = Control.createmock (Resultset.class);
      try {... mockresultset.next ();
      Expectlastcall (). Andreturn (True). times (3);
      Expectlastcall (). Andreturn (False). times (1);
      Mockresultset.getstring (1);
      Expectlastcall (). Andreturn ("demo_order_001"). times (1);
      Expectlastcall (). Andreturn ("demo_order_002"). times (1);
      Expectlastcall (). Andreturn ("demo_order_003"). times (1);
      Mockresultset.getstring (2);
      Expectlastcall (). Andreturn ("Asia Pacific"). times (1);
      Expectlastcall (). Andreturn ("Europe"). times (1);
      Expectlastcall (). Andreturn ("America"). times (1);
      Mockresultset.getdouble (3);
      Expectlastcall (). Andreturn (350.0). times (1);
      Expectlastcall (). Andreturn (1350.0). times (1);
      Expectlastcall (). Andreturn (5350.0). times (1);
      Control.replay (); .... int i = 0;
      String[] Pricelevels = {"Level_a", "Level_c", "level_e"};
        while (Mockresultset.next ()) {SalesOrder order = new Salesorderimpl ();
        Order.loaddatafromdb (Mockresultset);
        Assertequals (Order.getpricelevel (), pricelevels[i]);
      i++;
    } control.verify ();
    catch (Exception e) {e.printstacktrace (); }
  }
}

In this example, we first create the ResultSet mock object Moresultset and record the expected behavior of the mock object. We then called Control.replay () to place the state of the Mock object in the replay state. In the actual test phase, the Loaddatafromdb method of the Sales order object invokes the Mockresultset object's getString and GetDouble methods to read the data in the Mockresultset. The Sales Order object calculates the price level based on the data being read and compares it with the expected output. Validating the behavior of a Mock object

After using mock objects for the actual testing process, we have one more thing to do: Validate the number of method calls to mock objects.

To verify that the specified method call is really complete, we need to invoke the Verify method for validation. Like the replay method, you need to choose a different authentication method based on how the Mock object is generated. If the Mock object is generated by the Createmock static method provided by the Org.easymock.EasyMock class, then we also use the static method verify of the Easymock class for validation:

Verify (Mockresultset);

If the mock object is generated by the Createmock method provided by the Imockscontrol interface, then the Verify method provided by the interface, such as the Imockscontrol instance control in section 1th, is used:

Control.verify ();

The Mock objects generated by the control instance mockconnection, Mockstatement, and Mockresultset are validated. If the previous example Expectlastcall (). Andreturn (false) the expected number of times (1) is modified to 2, you will see in Eclipse: Figure 3:mock Object validation failed Mock object reuse

To avoid generating too many mock objects, EasyMock allows reuse of the original mock object. To reinitialize a Mock object, we can use the Reset method.  Similar to the replay and verify methods, EasyMock provides two ways to reset: (1) If a mock object is generated by a static method Createmock in the Org.easymock.EasyMock class, the mock object can be The static method of the EasyMock class is reset; (2) If the Mock method is generated by the Createmock method of the Imockscontrol instance, then the call to reset of the Imockscontrol instance method will create all the instances Mock object is reinitialized.

After reinitialization, the state of the Mock object is placed in the record state.

Back to the top 3. Using parameter matching to EasyMock predefined parameter matching in EasyMock

During the actual test using a Mock object, EasyMock matches the invocation of an expected method based on the method name and parameters. EasyMock matches the parameters by default using the Equals () method for comparison. This may cause some problems. For example, the Mockstatement object created in the previous chapter:

Mockstatement.executequery ("SELECT * from sales_order_table");
Expectlastcall (). Andstubreturn (Mockresultset);

In the actual call, we may encounter some keyword case problems in the SQL statement, such as a select as a select, then in the actual test, EasyMock's default match will consider the two parameters do not match, causing the Mock object's expected method is not invoked. EasyMock provides a flexible parameter matching method to solve this problem. If you are not concerned with the statements specifically executed by mockstatement and want all input strings to match this method invocation, you can replace the SQL statement in the parameter with the Anyobject method provided by the Org.easymock.EasyMock class:

Mockstatement.executequery (Anyobject ());
Expectlastcall (). Andstubreturn (Mockresultset);

The Anyobject method indicates that any input value matches the expected value. In addition to Anyobject, Easymock also provides a number of predefined parameter matching, some of which are more commonly used: Aryeq (X value): Matching by Arrays.equals (), for array objects; IsNull () : matches when the input value is null; Notnull (): matching when the input value is not NULL (x value): Match when the input value and expected value are the same object, lt (x value), Leq (x value), GEQ (x value), GT (x VA Lue): Match when the input value is less than, small equals, large equals, greater than the expected value, applicable to numeric type; startswith (string prefix), contains (string substring), EndsWith (string suffix) : When the input value starts with the expected value, contains the expected value, matches at the end of the expected value, applies to string type; matches (string regex): matches when the input value matches the regular expression, and applies to the string type. Custom parameter Matching

Predefined parameter matching may not satisfy some complex situations, at which point you need to define your own parameter matching device. In the previous section, we wanted to have a match that was not sensitive to the capitalization of keywords in SQL, and using anyobject was not a good choice. In this respect, we can define our own parameter matching device sqlequals.

To define a new parameter-matching device, you need to implement the Org.easymock.IArgumentMatcher interface. Where the matches (Object Actual) method should implement the matching logic of the input value and the expected value, and in the Appendto (StringBuffer buffer) method, you can add the information that needs to be displayed when the match fails. The following are some of the code implemented by Sqlequals (the complete code can be found in Src.zip): Listing 5: Custom parameter matching sqlequals

public class Sqlequals implements Iargumentmatcher {
  private String expectedsql = null;
  Public sqlequals (String expectedsql) {
    this.expectedsql = expectedsql;
  }
  ......
  Public boolean matches (Object actualsql) {
    if actualsql = null && expectedsql = null) return
      true;
    else if (actualsql instanceof string) return
      expectedsql.equalsignorecase ((String) actualsql);
    else return
      false;
  }

After implementing the Iargumentmatcher interface, we need to write a static method to wrap it. The implementation of this static method needs to report an object of Sqlequals through the Reportmatcher method to Easymock: Listing 6: Custom parameter matching sqlequals static method

public static string Sqlequals (string in) {
  reportmatcher (new Sqlequals (in));
  return in;
}

In this way, we can use the custom sqlequals matching device. We can modify the ExecuteQuery method in the previous example as follows:

Mockstatement.executequery (Sqlequals ("SELECT * from sales_order_table"));
Expectlastcall (). Andstubreturn (Mockresultset);


When a method call is made using ExecuteQuery ("SELECT * from Sales_order_table"), the expected behavior is matched.

Back to the top 4. Special Mock Object Type

So far, the mock objects we have created belong to the EasyMock default mock object type, which is insensitive to the order of invocation of the expected method and throws Assertionerror to unexpected method calls. In addition to this default mock type, EasyMock also provides some special mock types to support different requirements. Strick Mock Object

If a Mock object is created by Easymock.createmock () or Imockscontrol.createmock (), the order in which the method is called is not checked when the verify is validated. If you want to create a sequential, sensitive mock object (Strick mock) of the method invocation, you should use Easymock.createstrickmock () to create it, for example:

ResultSet Strickmockresultset = Createstrickmock (Resultset.class);

Similar to Createmock, we can also use the Imockscontrol instance to create a Strick Mock object:

Imockscontrol control = Easymock.createstrictcontrol ();
ResultSet Strickmockresultset = Control.createmock (Resultset.class);
Nice Mock Object

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.