Simulate objects and stubs, and simulate object stubs

Source: Internet
Author: User

Simulate objects and stubs, and simulate object stubs

In unit testing, the stubs and simulated objects are in a very important position. I will give you an understanding of the two.

1: What is interactive testing?

Three final result types of a work unit:

  • Value-based test: verifies the function return value.
  • Status-based testing: verifies the status changes after passing the tested Function
  • Interactive testing: verifies how an object sends messages (call methods) to another object (generally a third-party service)

Focus on interaction testing: if the final result of a specific unit of work is to call another object, InterAction testing is required. Simply put, you cannot determine whether you have called this method. Because its return value is void, you can only determine whether you have actually called this method in other ways. The whole process is interactive testing.

2: Simulated Object

What is a simulated object: The simulated object is also a pseudo object. It can verify whether the tested object has called the pseudo object as expected, so it can determine whether the unit test is successful or failed.

For example, because James has not finished his homework, the teacher asked James to go home late for an hour to write his homework. Then today, the teacher will go home early, let the shift leader Xiao Liang check whether James has stayed for an hour to write his homework. At this time, Xiao Liang is the pseudo object we are talking about. He checked whether James was going home an hour later.

3: differences between simulated objects and stubs

1: I already mentioned in the previous article. Now let's take a look.

Obviously, the object we asserted is a simulated object under the tested class.

This is an assertion on the simulated object.

In fact, they have very little difference. Their fundamental difference is that the stubs won't lead to test failure, but the simulated objects can (the stubs won't lead to test failure because they are for the tested classes, the opposite is true for simulated objects)

A simulated object is used to check whether your test fails. The following is an example.

4: Use of simulated objects and stubs

Now I reference an external LogService to specifically record error logs, but this log is of the void type and cannot be returned. This will be useful for simulating objects. First, we define a log service interface.

public interface ILogService    {        void ErrorLog(string message);    }

Tested code

Private readonly ILogService _ logService; public UserManager (ILogService logService) // simulate object injection {this. _ logService = logService;} public void RecordLog (string userName) {if (userName. length <= 4) // if the name Length is less than 4, log exceptions are recorded {_ logService. errorLog (userName );}}

Simulated Object

Public class FakeLogService: ILogService {public string Message; // record the error message public void ErrorLog (string Message) {this. message = Message ;}}

Test code

[Category ("Simulated Object")] [Test] public void recordlog_usernamereshort_calllogservice () {var mockService = new FakeLogService (); var userManager = new UserManager (mockService ); // inject the simulated object userManager. recordLog ("lp"); // record the error log Assert. areEqual ("lp", mockService. message); // if the error Message is the same as that of the simulated object, it indicates that I have called this method and passed the correct value}

Let's take a look at the test results:

We found that the test passed, which indicates that our method has been correctly called and passed the value to log service. This test ensures that there is no error in calling the LOG method.

Use both the stub and the simulated object

Sometimes a method has two methods that fail to return values. At this time, you may need to determine which is the stub and which is the simulated object.

Now we have another requirement. If an error log exception occurs, we need to send an email to the system administrator. At this time, we find that we have two functions without return values, it is not recommended to write two simulated objects, which will lead to confusion. You do not know which method has an error (because the assertions are intended for simulated objects)

First define an email sending Interface

public interface IEmailService    {        void SendEmail(string user, string subject, string content);    }

Simulate object to implement this interface

public class FackEmailService : IEmailService    {        public string User { get; set; }        public string Subject { get; set; }        public string Content { get; set; }        public void SendEmail(string user, string subject, string content)        {            this.User = user;            this.Subject = subject;            this.Content = content;        }    }

We are looking at the tested code.

Public class UserManager {public void RecordLog (string userName) {try {if (userName. length <= 4) // if the name Length is less than 4, log exceptions are recorded {LogManager (). errorLog (userName) ;}} catch (Exception ex) {EmailService (). sendEmail ("lp", "subject", ex. message) ;}} protected virtual ILogService LogManager () // The underlying layer can be replaced by {return new LogService ();}
protectedvirtual IEmailService EmailService()
{
returnnew EmailService();
} }

Create new class inheritance to be tested class to complete underlying replacement

    public class TestUserManager : UserManager    {        private readonly ILogService _logService;        private readonly IEmailService _emailService;        public TestUserManager(ILogService logService, IEmailService emailService)        {            _logService = logService;            _emailService = emailService;        }        public override IEmailService EmailService()        {            return _emailService;        }        public override ILogService LogManager()        {            return _logService;        }    }

Test code

[Test] public void RecordLog_EmailServiceThrows_SendsEmail () {var stubLogService = new FakeLogService () {Exception = new Exception ("fack exception ")}; // The log simulation object throws an exception (this is a stub) var mokeEmailService = new FackEmailService (); var testUser = new TestUserManager (stubLogService, mokeEmailService ); // inject the stub and the simulated object testUser. recordLog ("lp"); StringAssert. contains ("lp", mokeEmailService. user); StringAssert. contains ("subject", mokeEmailService. subject); StringAssert. contains ("fack exception", mokeEmailService. content );}

Let's take a look at the test results.

You can also encapsulate three attributes into one entity to assert an object.

5. pseudo object chain

What is an object chain: that is, the attribute of an object is another object, and the attribute of this object is another object. In this example, the ConfigurationManager. ConnectionStrings [0]. ConnectionString is an object chain.

If we find that two objects need to be forged during the test, if many objects need to be forged, more may be forged, therefore, when refactoring the code, we need to consider the following measurable code so that testing can directly replace

    protected virtual string GetConnectionString()        {            return ConfigurationManager.ConnectionStrings[0].ConnectionString;        }
6: Problems with manually simulating objects and stubs
  • It takes time to write simulation objects and stubs
  • If the interface has many methods, attributes, and events, it will be particularly difficult to compile them.
  • Multiple assertions are required to verify that all parameters passed by the caller to another method are correct.
  • Some simulated objects write less reusability for specific methods.

 

Related Article

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.