Mock object in unit test

Source: Internet
Author: User

Let's take a look at it.

 

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 you are not careful, you may eventually find that you have initialized almost every component of the system, this is just to create enough runtime environments for a test to run. After a long time, it seems that we are against 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 such a situation. After we build a realistic 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 produce some minor problems. 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, what should we 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 see the importance of interface-based programming, because the tested Code only references objects through interfaces, therefore, 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, after five o'clock P.M., the audio files will be played to remind everyone to get off work. If we want to use real objects for testing, we have to wait until five o'clock P.M. and put our ears next to the speaker... we don't want to be so stupid. We should use the mock object 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 every time, the problem is solved, but it seems to be a little troublesome. Don't worry, there are already some third-party ready-made mock objects for us to use. Testing with mock object is mainly used to simulate structures that are not easy to construct in the application (for example, httpservletrequest must be constructed in the servlet container) or more complex objects (such as the resultset object in JDBC) to make the test run smoothly. Currently, the main mock testing tools in the Java camp include jmock, mockcreator, mockrunner, easymock, and mockmaker. in Microsoft's. Net camp, they are mainly nmock and. netmock.

The following uses easymock to simulate and test the servlet component as an example. The Code is as follows: Compile and run it as a test case. Both test methods are successful. 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.

 

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. createcontrol (httpservletrequest. class); // get a mock httpservletrequest object mockrequest = (httpservletrequest) control. getmock (); // set the mock httpservletrequest object method mockrequest to be called. getparameter ("name"); // set the expected return value of the call method, and specify the number of calls. // The following two parameters indicate that the call is performed at least once and the call is controlled at most once. setreturnvalue ("kongxx", 1, 1); // sets the status of mock httpservletrequest, // indicates that the mock httpservletrequest object can be controlled. replay (); // use 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 programs to generate, C ++ still needs to connect at the final stage to generate a whole program, the flexibility is incomparable to the mechanism of Java source code. Java classes are independent, and those packaged classes are independent. They are connected only when loaded, when the code is loaded, 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 to this, with this, 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.

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.