Using MOCK objects for unit testing

Source: Internet
Author: User
Tags documentation

1. What went wrong.

The goal of unit testing is to validate only one method at a time, small steps forward, fine-grained testing, but what if a method relies on something else that is difficult to manipulate, such as a network connection, a database connection, or a servlet container?

If your test relies on other parts of the system, even on a number of other parts of the system. In this case, if you are not careful, you may end up finding that you have almost initialized each component of the system, and this is just to create enough running environments for a test so that they can run. For the most of the day, it looks like we're a little out of the test. This not only consumes time, it also introduces a lot of coupling factors into the test process, for example, someone may have been interested in a dash to change an interface or a database of a table, suddenly, your humble unit test mysteriously hung off. After this happens a few times, even the most patient developers will be discouraged, or even eventually give up all the tests, so the consequences can not be imagined.

Let's look at a more specific situation: in the actual object-oriented software design, we often encounter the situation, we have to build the real object, the object is through a series of interfaces to achieve. This is the most natural thing to do in object-oriented design, but with the development of software testing requirements, this can have some minor problems. For example, user A now gets the interface provided by User B, who implements his own requirements based on this interface, but after user a compiles his own code, he wants a simple simulation test. This is also a very realistic question. Can we simply implement a proxy class for this interface to test the simulation and expect the code to generate its own results?

Fortunately, there is a test pattern that can help us: mock objects. Mock objects are substitutes for real objects in the debug period.

2. Now you need a mock object.

Tim MacKinnon gives us some advice on when to mock objects:

-----An uncertain behavior (produce unpredictable results, such as stock quotes) for real objects.

-----Real objects are difficult to create (e.g. specific web containers)

-----Certain behaviors of real objects are difficult to trigger (such as network errors)

-----The real situation makes the program slow to run

-----Real object has a user interface

-----test needs to ask the real object how it was invoked (for example, the test might need to verify that a callback function was invoked)

-----Real objects don't really exist (this is a common problem when you need to deal with other development groups, or new hardware systems)

3. How to implement a mock object.

When testing with mock objects, we need a total of 3 steps, respectively:

-----Use an interface to describe this object

-----implement this interface for product code

-----implement this interface in a mock object for testing purposes

Here again we see the importance of programming for interfaces, because the code being tested only refers to an object through an interface, it can be completely unaware of whether it is referring to a real object or a mock object, and here's a real example: an alarm clock is based on time to remind the service, If after 5 o'clock in the afternoon to play audio files to remind everyone to work, if we want to use the real object to test the words can only wait until five o'clock in the afternoon, and then put the ear next to the speaker ... We don't want to be so stupid, we should use mock objects to test, so we can simulate control time without waiting for the clock to turn to 5 o'clock in the afternoon. Here's the code:

Public interface Environmental {    
Private Boolean playedwav = false;
Public long getTime ();
public void Playwavfile (String fileName);
public boolean wavwasplayed ();
public void Resetwav ();
}

The real implementation code:

public class Systemenvironment implements environmental {    
Public long GetTime () {
return System.currenttimemillis ();
}
public void Playwavfile (String fileName) {
Playedwav = true;
}
public Boolean wavwasplayed () {
return playedwav;
}
public void Resetwav () {
Playedwav = false;
}
}

The following are mock objects:

public class Mocksystemenvironment implements environmental {    
Private long currenttime;
Public long GetTime () {
return currenttime;
}
public void SetTime (long currenttime) {
This.currenttime = currenttime;
}
public void Playwavfile (String fileName) {
Playedwav = true;
}
public Boolean wavwasplayed () {
return playedwav;
}
public void Resetwav () {
Playedwav = false;
}
}

The following is a specific class that invokes GetTime:

Import Java.util.Calendar;    

public class Checker {
Private environmental env;
Public Checker (environmental env) {
This.env = env;
}
public void Reminder () {
Calendar cal = Calendar.getinstance ();
Cal.settimeinmills (Env.gettime ());
int hour = Cal.get (Calendar.hour_of_day);
if (hour >= 17) {
Env.playwavfile ("Quit_whistle.wav");
}
}
}

The measured code using Env.gettime () does not know the difference between the test environment and the real environment, as they all implement the same interface. Now, you can use mock objects to write tests by setting the time to a known value and checking whether the behavior is as expected.

Import Java.util.Calendar;
Import Junit.framework.TestCase;

public class Testchecker extends TestCase {
public void Testquittingtime () {
Mocksystemenvironment env = new Mocksystemenvironment ();
Calendar cal = Calendar.getinstance ();
Cal.set (Calendar.year, 2006);
Cal.set (Calendar.month, 11);
Cal.set (calendar.day_of_month,7);
Cal.set (Calendar.hour_of_day, 16);

Cal.set (Calendar.minute, 55);
Long T1 = Cal.gettimeinmillis ();
Env.settime (t1);
Checker Checker = new Checker (env);
Checker.reminder ();
Assertfalse (env.wavwasplayed ());
T1 + = (5*60*1000);
Env.settime (t1);
Checker.reminder ();
Asserttrue (env.wavwasplayed ());
Env.resetwav ();
T1 + = 2*60*60*1000;
Env.settime (t1);
Checker.reminder ();
Asserttrue (env.wavwasplayed ());
}
}

This is all a mock object: something that disguises the real world and allows you to concentrate on testing your own code.

4. There seems to be some trouble

If you write a mock object on your own every time like the one above, the problem is solved, but there seems to be some trouble, don't worry, there are some third-party mock objects ready for us to use. Testing with mock object is primarily used to simulate objects that are not easily constructed in an application (such as HttpServletRequest must be constructed in a servlet container) or are more complex (such as the ResultSet object in JDBC) The tools that make the test work smoothly. Currently, the main mock test tools in the Java camp are Jmock,mockcreator,mockrunner,easymock,mockmaker, etc., at Microsoft. NET camp is mainly NMock,. Netmock and so on.

The following is an example of using the Easymock simulation test servlet component as follows: compiling and running it as a test case reveals that two test methods are tested successfully. We can see that Easymock has helped us implement some of the servlet component mock objects so that we can get rid of the Web container and the servlet container to easily test the servlet.

 import org.easymock.*;    
Import junit.framework.*;
Import javax.servlet.http.*;

public class Mockrequesttest extends testcase{
Private Mockcontrol control;
Private HttpServletRequest mockrequest;
public void Testmockrequest () {
///Create a mock HttpServletRequest Mockcontrol object
Control = mockcontrol.c Reatecontrol (Httpservletrequest.class);
//Get a mock HttpServletRequest object
Mockrequest = (httpservletrequest) control.getmock ();
//Sets the method
Mockrequest.getparameter ("name") of the mock HttpServletRequest object that is expected to be invoked;
//sets the return value expected by the calling method and specifies the number of calls
//The following two parameters represent the minimum call once, and the maximum call once
Control.setreturnvalue ("Kongxx", 1, 1);
//sets the state of the mock httpservletrequest,
//indicates that this mock HttpServletRequest object can be used
Control.replay ();
//Use assertion Check to call
Assertequals ("Kongxx", Mockrequest.getparameter ("name"));
//Validate the expected call
Control.verify ();
}
}

Compiled and run as a test case, you will find that two test methods are tested successfully. We can see that Easymock has helped us implement some of the servlet component mock objects so that we can get rid of the Web container and the servlet container to easily test the servlet.

5. What is the underlying technology?

Let's recall, if the user uses C + + and Java program generation, C + + in the final stage still need to connect to generate a whole program, which in the flexibility of the Java source code is not comparable to the mechanism, the Java classes are independent, the packaging of those classes are independent, The connection is made only when it is loaded in. This is when the code is loaded, we can also perform a lot of actions, such as inserting some related business requirements, which is also a focus of AOP, the implementation of the Javassit code base is similar to this, it is the use of these, so the Java implementation of mock objects is very simple.

6. Some of the relevant resources

Mockobject's home page http://www.mockobjects.com/introduces the basic concepts of key mock object and the main mock test tool currently in various environments.

Jmock's home page http://www.jmock.org/can get the latest code and development kits for Jmock, as well as some documentation.

Easymock's home page http://www.easymock.org/can get the latest code and development kits for Jmock, as well as some documentation.

NMock's homepage, http://www.nmock.org/, is described at Microsoft. NET platform, the development tool for mock testing.
Turn from: http://tech.ccidnet.com/art/3539/20070809/1172211_1.html

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.