Use a mock object for unit testing

Source: Internet
Author: User

1. What's wrong?

The objective of unit testing is to verify only one method at a time, with small steps forward and fine-grained tests. However, if a method is dependent on other hard-to-manipulate things, such as network connections and database connections, or servlet container, what should we do?

What if your test depends on other parts of the system, or even multiple parts of the system? In this case, if
If you are not careful, you may eventually find that you have initialized almost every component of the system, just to create enough runtime environments for a test to run. Busy for a long time, it looks good to us
It seems a little contrary to the original intention of the test. This not only consumes time, but also introduces a lot of coupling factors to the test process. For example, someone may be eager to change an interface or a table in the database. Suddenly, your humble unit test is mysterious. After this happens several times, even the most patient developer will be discouraged, and even eventually give up all the tests, then the consequences will be unimaginable.

Let's look at a more specific situation: in the actual object-oriented software design, we often encounter this
After we build a real object, objects are implemented through a series of interfaces. This is the most natural thing in object-oriented design, but with the development of software testing requirements, this will
There are some minor issues. For example, user a now obtains an interface provided by user B and implements his own needs based on this interface. However, after user a compiles his own code, he wants to simulate and test it, how
What should I do? This is also a very practical issue. 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 mode that can help us: mock objects. The mock object is a replacement of the real object during the debugging period.

2. Do I need a mock object now?

Tim macinnon gave us some suggestions on when to use the mock object:

----- The real object has uncertain behavior (produce unpredictable results, such as stock quotations)

----- Real objects are difficult to create (such as specific Web containers)

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

----- The real situation makes the program run slowly

----- Real objects have user interfaces

----- The test needs to ask how the real object is called (for example, the test may need to verify whether a callback function is called)

----- Real objects do not actually exist (this is a common problem when dealing with other development groups or new hardware systems)

3. How to implement a mock object?

When testing with a mock object, we need three steps in total:

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

----- Implement this interface for the product code

----- Implement this interface in the mock object for the purpose of testing

Once again, we can see the importance of interface-based programming, because the tested code will only be referenced through the interface.
So it does not know whether the referenced object is a real object or a mock object. Let's take a look at the actual example: an alarm is triggered by time, if it is over five o'clock P.M.,
Put the audio file to remind everyone that we are off duty. If we want to use real objects for testing, we can only wait until five o'clock P.M., and then put our ears next to the speaker... we don't want to be so stupid. We should use it.
The mock object is used for testing, so that we can simulate the control time, instead of waiting for the clock to go to five o'clock P.M. The following code is used:


       
        public interface Environmental {    
        
private boolean playedWav = false;
public long getTime();
public void playWavFile(String fileName);
public boolean wavWasPlayed();
public void resetWav();
}

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 is a mock object:

     
      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 calls 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 tested code using env. gettime () does not know the differences between the test environment and the real environment, because they all implement the same interface. Now, you can use the mock object to set the time to a known value and check whether the behavior is written 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 about mock objects: Some behaviors disguised as real-world, allowing you to focus on testing your code.

4. There seems to be some trouble

If you write a specific mock object as you did above each time, although the problem is solved, it seems that there is some trouble
Don't worry. some third-party mock objects are ready for use. Use mock
Object testing is mainly used to simulate those that are not easily constructed in the application (for example, httpservletrequest must be constructed in the servlet container) or
Tools that make the test run smoothly by using complex objects (such as the resultset object in JDBC. Currently, the main mock testing tools in the Java camp are:
Jmock, mockcreator, mockrunner, easymock, mockmaker, etc. In Microsoft's. Net camp
Nmock,. netmock, etc.

The following uses easymock as an example to simulate and test the servlet component. The Code is as follows:
Compile and use it as a test
Run in case, you will find that both test methods are successful. We can see that easymock has helped us implement the mock object of some servlet components, so that we can place
Take off the Web Container and 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 mockcontrol object for mock httpservletrequest
Control = mockcontrol. createcontrol (httpservletrequest. Class );
// Obtain a mock httpservletrequest object
Mockrequest = (httpservletrequest) control. getmock ();
// Set the mock httpservletrequest object to be called
Mockrequest. getparameter ("name ");
// Set the expected return value of the call method and specify the number of calls
// The following two parameters indicate at least one call and at most one call.
Control. setreturnvalue ("kongxx", 1, 1 );
// Set the status of mock httpservletrequest,
// Indicates that the mock httpservletrequest object can be used.
Control. Replay ();
// Use assertion to check the call
Assertequals ("kongxx", mockrequest. getparameter ("name "));
// Verify the expected call
Control. Verify ();
}
}

Compile and run it as a test case. Both test methods are successfully tested. We can see that easymock has helped us implement the mock objects of some servlet components, so that we can get rid of the Web Container and servlet container to easily test the servlet.

5. What is the underlying technology?

Let's recall that if you use C ++ and Java to generate programs, C ++ will be in the final stage.
You still need to connect to generate a whole program. This is incomparable with the Java source code mechanism. Java classes are independent and those packaged classes are independent, only loaded
Line join. When the code is loaded in, we can execute a lot of actions, such as inserting some related business requirements, which is also a focus of AOP. The implementation of the pull sit code library is similar
Therefore, it is very easy to use Java to implement mock objects.

6. Related Resources

Mockobject home page http://www.mockobjects.com/introduces the basic concepts of the key mock object and the main mock testing tools in various environments.

Jmock home page http://www.jmock.org/get the latest code and Development Kit for jmock, as well as some instructions.

Easymock home page http://www.easymock.org/get the latest code and Development Kit for jmock, as well as some instructions.

Nmock home page http://www.nmock.org/describes the development tools for mock testing on the Microsoft. NET platform.


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.