Previous article [small North de programming notes]: Lesson 03 play xunit.net Fixture (Upper) "to introduce the way xunit.net share data, Test case Constructor & IDisposable.Dispose, C Lass level of fixture:iclassfixture. In this article, we go on to explain what's going on, and review what this article is about:
- Xunit.net How to share data (top)
- Constructor for Test Case & IDisposable.Dispose (top)
- Class-level fixture:iclassfixture (top)
- Collection level of fixture:icollectionfixture (bottom)
- Dependency Injection and output log (bottom)
(iv) Fixture:icollectionfixture at the collection level
Recall our virtual application scenario in the previous article. Among them, about question three: "Create a database connection at the application level uniformly, the database connection used by the Test case is the same (or unified management)". For the implementation of this requirement, we can use Xunit.net's icollectionfixture to achieve. The collection level of fixture gives us the ability to share data across multiple test classes. All test cases that are contained under the same collection share a copy of the context data. Let's take a look at the function of the virtual scene problem three.
Step 01: Define Collectionfixture (databasefixture in emoD)
Like Classfixture, a custom collectionfixture class needs to complete its constructor & IDisposable.Dispose definition. The construction of the Collectionfixture class and the Dispose method will eventually be called before and after all the case executions of the test class that are tagged with the collection. That is, all tags that use the collection test method run before the Collectionfixture constructor is executed. The IDisposable.Dispose function of Collectionfixture is executed after all of the test methods that use the collection are finished running. We define a databasefixture with the following code:
1 Public classdatabasefixture:idisposable2 {3 Public ObjectDatabasecontext {Get;Set; }4 5 Public Static intExecutecount {Get;Set; }6 7 Publicdatabasefixture ()8 {9executecount++;Ten //initializing a data connection One } A - Public voidDispose () - { the //Destroying data Connections - } -}
Code that omits the creation and destruction of the database connection. Only a property of type object is used to represent the database context, and a static variable, Executecount, is used to mark the usage frequency of the constructor.
Step 02: Define collection.
For Classfixture, because it is a class-level data share. So ... xunit.net provides the ability to implement data sharing gracefully by inheriting the Iclassfixture interface directly from the class and combining the constructor injection. And how is data sharing for collection (a group of classes) implemented? Let's take a look at the sample code:
1 /// 2 /// Define the collection name, indicating the fixture /// </SUMMARY> 4 [ Collectiondefinition ( databasecollection )] public class Databasecollection:icollectionfixture<databasefixture>6 { 7 }
As you can see, we define a class databasecollection with no content, and the main function of this class is to define a collection named "databasecollection" (which can be different from the class name). and indicates that the collection corresponds to the fixture. It is necessary to note that Icollectionfixture and iclassfixture are a generic markup interface (that is, there is no method to implement, just to mark the type of the corresponding fixture). The definition collection code uses the Collectiondefinition tag, which is defined as follows:
1 namespaceXunit2 {3 //Summary:4 //used to declare a test collection container class. The container class gives5 //developers a place to attach interfaces like xunit.iclassfixture<tfixture>6 //And xunit.icollectionfixture<tfixture> that'll be applied to all tests7 //Classes that is members of the the test collection.8[AttributeUsage (attributetargets.class, AllowMultiple =false, inherited =false)]9 Public Sealed classCollectiondefinitionattribute:attributeTen { One //Summary: A //Initializes a new instance of the Xunit.collectiondefinitionattribute class. - // - //Parameters: the //Name: - //The test collection name. - PublicCollectiondefinitionattribute (stringname); - } +}
The class marked by Collectiondefinition is instantiated as an object at run time by the Xunit.net framework, which will be used to mark other classes (if interested, go to GitHub to see Xunit.net's source code). This requires a collectionname as a parameter, which will be tagged with the class that needs to use this collectionfixture.
Step 03: Use collection to mark test classes that need to use fixtrue.
Xunit.net provides the collection class, which serves to indicate which collection the test class needs to use. All the test methods that are marked in the collection test class call the corresponding Collectionfixture constructor once before it is run. Once all methods have been run, the collectionfixture idisposable.dispose function (if defined) is called once. It is worth noting that the test class still gets the Databasefixture instance object in the same way as the constructor injection . So, let's take a look at the demo:
1[Collection ("DatabaseCollection")]2 Public classsharedcontext_collectionfixture_013 {4 Privatedatabasefixture _dbfixture;5 PrivateItestoutputhelper _output;6 Publicsharedcontext_collectionfixture_01 (itestoutputhelper output, databasefixture dbfixture)7 {8_dbfixture =dbfixture;9_output =output;Ten } One A[Fact (DisplayName ="SharedContext.CollectionFixture.Case01")] - Public voidTestCase01 () - { the_output. WriteLine ("Execute collectionfixture Case 01!"); -_output. WriteLine ("databasefixture Executecount is: {0}", databasefixture.executecount); - } - } + -[Collection ("DatabaseCollection")] + Public classsharedcontext_collectionfixture_02 A { at Privatedatabasefixture _dbfixture; - PrivateItestoutputhelper _output; - Publicsharedcontext_collectionfixture_02 (databasefixture dbfixture, itestoutputhelper output) - { -_dbfixture =dbfixture; -_output =output; in } - to[Fact (DisplayName ="SHAREDCONTEXT.COLLECTIONFIXTURE.CASE02")] + Public voidTestCase01 () - { the_output. WriteLine ("Execute collectionfixture Case 02!"); *_output. WriteLine ("databasefixture Executecount is: {0}", databasefixture.executecount); $ }Panax Notoginseng}
Dome defines two test classes, one for each test class, and collection for the name of the collection to use. The results of the operation are as follows:
As you can see, the constructors in Databasefixture are executed only once (IDisposable.Dispose also has the same logic). Therefore, in the actual unit tests, we can build and manage database connections here to save resource overhead.
(v) Dependency Injection and output logs
Dependency injection is an important principle of OOP, which is used to reduce the coupling problem of computer programs. is now at the heart of many different areas of software frameworks. On the concept of dependency injection, I think we are not unfamiliar. Here I have listed several main ways of dependency injection:
- Type 1 (interface-based): A service object needs to implement a specialized interface that provides an object that can be reused for this object lookup dependency (other services).
- Type 2 (Setter-based): Specifies a service for a service object through the JavaBean property (setter method).
- Type 3 (constructor-based): Specifies the service for the serviced object through the parameters of the constructor.
Here comes the dependency injection, mainly wants to share with you oneself to Xunit.net's design idea the little understanding. I have mentioned in the first Xunit.net series article [small North de programming notes]: Lesson 01 Topsy xunit.net Overview: One of the improvements in xunit.net is that the attribute tag is no longer used when handling the initialization and cleanup methods of each test case. Instead, the constructors and IDisposable.Dispose methods are used. A direct benefit of this is to make dependency injection easier to use in xunit.net. In the previous example, the various levels of fixture, log objects ... Is through the way of dependency injection simple, elegant is obtained by us. For the log object, the user does not have to pay attention to where it will output (this is determined by the tool that runs the case < that is runner>), and we don't even care how it is instantiated. When running a case with a different runner, runner will implement a set of its own output for the Xunit.net interface. Let's review the output interface and how it is used:
1 namespacexunit.abstractions2 {3 Public InterfaceItestoutputhelper4 {5 voidWriteLine (stringmessage);6 voidWriteLine (stringFormatparams Object[] args);7 }8}
As you can see, Itestoutputhelper defines two output methods that the consumer can get to the output object provided by the runtime runner, in the following way (constructor injection). In the case of object instantiation, management and other operations are managed by the runner (program) that runs the cases. I'll show you how to customize the runner and the meaning of the custom runner, and I'll stop here.
1 Public classSharedcontext_classfixture:iclassfixture<singlebrowserfixture>2 {3 Itestoutputhelper _output;4 Publicsharedcontext_classfixture (itestoutputhelper output, singlebrowserfixture fixture)5 {6_output =output;7 }8 #regionTest case9[Fact (DisplayName ="SharedContext.ClassFixture.Case01")]Ten Public voidTestCase01 () One { A_output. WriteLine ("Log here"); - } - #endregionTest case the}
The use of the log object itself is simple and is pulled out separately to show you the artisan spirit of xunit.net design (closer to the designer's intentions). Many of the frame-level changes are small (NUnit uses attribute tags to mark the initialization method, while Xunit.net uses constructors), but with a deep intent. So ... Let's take it easy ~ ~ ~
These two articles mainly discuss the following issues with you:
- Xunit.net How to share data
- Test Case Constructor & IDisposable.Dispose
- Class-Level Fixture:iclassfixture
- Collection level of Fixture:icollectionfixture
- Dependency Injection and output logs
About the basic use of Xunit.net fixture first introduced here, the next for you to explain how to expand the fixture level xunit.net function. So, let's take a look at Xunit.net's scalability.
Little North de series articles:
[Small North de programming notes]: Selenium for C # tutorial
[Small North de programming notes]:c# Evolutionary history] (unfinished)
[Small North de programming notes]: Topsy xunit.net (unfinished)
Demo Address: Https://github.com/DemoCnblogs/xUnit.Net
If you think this article is good or something, you can click on the bottom right corner of the
"Recommended" button, because your support is I continue to write, share the most power! Small North @north Source: Http://www.cnblogs.com/NorthAlan Statement: The original text of this blog only represents my work in a certain time to summarize the views or conclusions, and I do not have a direct interest in the unit. Non-commercial, unauthorized, post please keep the status quo, reprint must retain this paragraph statement, and in the article page obvious location to the original connection.
[Small North de programming notes]: Lesson 04 Play Turn Xunit.net Fixture (under)