Reading notes-unit test Art (iii)-using pile objects to lift dependencies

Source: Internet
Author: User

First, several concepts 1. What is external dependency

External dependency refers to the object that the code interacts with in the system, and it cannot be controlled by human beings.

The most common examples are file systems, threads, memory, and time, and we use pile objects to handle external dependency problems.

2. What is a pile object

The pile object is a substitute for the existing dependence in the system, which can be controlled artificially.

By using a pile object, you can test the code directly without involving dependencies.

3. What is refactoring

Refactoring refers to a behavior that changes code design without affecting existing functionality

4. What is a seam

Seams are places in your code where you can insert different functions, such as pile object classes.

II. release of Reliance

Abstract an interface

namespace logan.interface{    publicInterface  iextensionmanager    {        bool IsValid (string  fileName);}    }

Specific classes that implement interfaces

namespacelogan.implement{ Public classFileextensionmanager:iextensionmanager { Public BOOLIsValid (stringfileName) {            if(string. IsNullOrEmpty (FileName)) {Throw NewArgumentException ("No filename provided!"); }            if(!filename.endswith (". SLF"))            {                return false; }            Else            {                return true; }        }    }}

Write a Pile object class that implements the interface

Regardless of the extension class of the file, this pile object class always returns True

 Public class stubextensionmanager:iextensionmanager{    publicbool IsValid (string  FileName)    {        returntrue;    }}

Writing the method under test

An existing interface and two classes to implement the interface, but the test class or directly invoke the "true object";

At this point we need to introduce seams in the code so that we can use the pile object

The realization of injecting the pile object into the tested class;

Receives an interface at the constructor level;

namespace logan{    publicclass  loganalyzer    {        publicBOOL Isvalidlogfilename (string  fileName)        {            =new  Fileextensionmanager ( );             return Mgr. IsValid (fileName);     }}}
Iii. injecting the pile object into the class being tested--the constructor function

1. Rewrite LogAnalyzer.cs

namespacelogan{ Public classLoganalyzer {PrivateIextensionmanager Manager; /// <summary>        ///Create a new object in production code/// </summary>         PublicLoganalyzer () {Manager=NewFileextensionmanager (); }        /// <summary>        ///define the constructors that are available for test calls/// </summary>        /// <param name= "Mgr" ></param>         PublicLoganalyzer (Iextensionmanager Mgr) {Manager=Mgr; }         Public BOOLIsvalidlogfilename (stringfileName) {            returnManager.        IsValid (FileName); }    }}
2. Writing the Pile object
 Public class Stubextensionmanager:iextensionmanager {     publicbool  shouldextensionbevalid;      publicbool IsValid (string  fileName)     {         return  shouldextensionbevalid;}     }
3. Writing test methods
[Testfixture] Public classloganalyzertest{[Test] Public voidisvalidfilename_validfilelowercased_returntrue () {Stubextensionmanager Myfakemanager=NewStubextensionmanager (); Myfakemanager.shouldextensionbevalid=true; Loganalyzer Analyzer=NewLoganalyzer (Myfakemanager); BOOLresult = Analyzer. Isvalidlogfilename ("HAHA.SLF"); Assert.istrue (Result,"filename shoud be valid!"); }}

4. Problems existing in the method of constructor injection

If the code under test needs more than one pile object to function properly, you need to add more constructors, which can cause great distress and even reduce the readability and maintainability of the code.

5. When to use the constructor injection method

Using constructors, you can tell the API consumer well: "These parameters are required, and all parameters must be passed in when you create the object"

If you want these dependencies to become optional, you can use attribute injection

Iv. injecting the pile object into the test class-attribute injection

1. Rewrite LogAnalyzer.cs

namespacelogan{ Public classLoganalyzer {PrivateIextensionmanager Manager; /// <summary>        ///Create a new object in production code/// </summary>         PublicLoganalyzer () {Manager=NewFileextensionmanager (); }        /// <summary>        ///allow dependency through property setting/// </summary>        /// <param name= "Mgr" ></param>         PublicIextensionmanager Extensionmanager {Get{returnManager;} Set{manager =value;} }         Public BOOLIsvalidlogfilename (stringfileName) {            returnManager.        IsValid (FileName); }    }}
2. Writing the Pile object class
 Public class stubextensionmanager:iextensionmanager{    publicbool  shouldextensionbevalid;     publicbool IsValid (string  fileName)    {        return shouldextensionbevalid;}    }
3. Writing test methods
[Testfixture] Public classloganalyzertest{[Test] Public voidisvalidfilename_validfilelowercased_returntrue () {Stubextensionmanager Myfakemanager=NewStubextensionmanager (); Myfakemanager.shouldextensionbevalid=true; Loganalyzer Analyzer=NewLoganalyzer (); Analyzer. Extensionmanager=Myfakemanager; BOOLresult = Analyzer. Isvalidlogfilename ("HAHA.SLF"); Assert.istrue (Result,"filename shoud be valid!"); }}
V. Injecting the pile object into the test class-factory method

1. Writing LogAnalyzer.cs

namespacelogan{ Public classLoganalyzer {PrivateIextensionmanager Manager; /// <summary>        ///using the factory in production code/// </summary>        /// <param name= "Mgr" ></param>         PublicLoganalyzer () {Manager=extensionmanagerfactory.create (); }         Public BOOLIsvalidlogfilename (stringfileName) {            returnManager.        IsValid (FileName); }    }}

2. Writing test methods

[Testfixture] Public classloganalyzertest{[Test] Public voidisvalidfilename_validfilelowercased_returntrue () {Stubextensionmanager Myfakemanager=NewStubextensionmanager (); Myfakemanager.shouldextensionbevalid=true; //assign the pile object to the factory classExtensionmanagerfactory.setmanager (Myfakemanager); Loganalyzer Analyzer=NewLoganalyzer (); BOOLresult = Analyzer. Isvalidlogfilename ("HAHA.SLF"); Assert.istrue (Result,"filename shoud be valid!"); }}

Reading notes-unit test Art (iii)-using pile objects to lift dependencies

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.