You can use the following methods to expand nunit: use custom constraints to expand the nunit framework referenced in our test project, for our own test project; Use addin to expand the nuint core, this will affect the compilation and running of the test project by nuint. In addition, it can also extend the GUI running tool.
Custom constraints (nunit 2.4/2.5)
Inherit abstract classesConstraintYou can implement the custom constraint custom constraints. It tests a real value and generates appropriate prompts.
public abstract class Constraint{ ... public abstract bool Matches( object actual ); public virtual bool Matches( ActualValueDelegate del ); public virtual bool Matches<T>( ref T actual ); public abstract void WriteDescriptionTo( MessageWriter writer ); public virtual void WriteMessageTo( MessageWriter writer ); public virtual void WriteActualValueTo( MessageWriter writer );...}
This class is not just listed above. It can be expanded to include two abstract methods that you must implement and four virtual methods. They contain default implementations, you can rewrite them according to your own meaning. The inherited subclass should save the actual values used for matching in a Protected actual field for future use. Messagewriter is an abstract class that is implemented by the textmessagewriter class. View the Code with built-in constraints to learn how to customize error information.
The following is the implementation of the emptystringconstraint class in a nuint:
/// <Summary> /// emptystringconstraint is used to test whether a string is empty. /// </Summary> public class emptystringconstraint: constraint {// <summary> /// test whether the specified value meets the constraints. /// </Summary> /// <Param name = "actual"> value to be tested </param> // <returns> If the test succeeds, true is returned, false is returned for failure </returns> Public override bool matches (Object actual) {// the actual value is saved to the actual field of the base class for later use this. actual = actual; If (! (Actual is string) return false; Return (string) Actual = string. empty ;} /// <summary> /// write the constraint description to messagewriter /// </Summary> /// <Param name = "Writer"> writer that represents the description </param> public override void writedescriptionto (messagewriter writer) {writer. write ("<empty> ");}}
Syntax implementation of custom constraints: nunit itself has syntax implementation of some classes containing specific constraints. Of course, nuint does not implement syntax for custom constraints unless we implement it ourselves. However, we can useMatches (constraint)Write the Code as follows:
MyConstraint myConstraint = new MyConstraint();Assert.That( myArray, Has.Some.Matches(myConstraint) );
Nunit addins
Nunit early identification tests are performed by inheriting the test base class and Methods Starting with test. However, it is marked as a feature from 2.0. However, after removing the subclass Inheritance Mechanism, we also lost a simple extension nunit internal behavior method. In this case, addins fills this gap so that we can introduce new behaviors or modify the original behaviors without modifying the nuint itself.
Nunit provides several extension points because nunit runs tests on different hosts and application domains. There are three types of extension points: Core, client, and GUI. That is, we can expand nunit in these three aspects.
With The addin plug-in, you can add multiple extensions to any extension point. Each extension must indicate the extension type, so the extension host knows how to motivate them: the current version only supports the extension of the core type.
Nunit checks all the assemblies in the bin/addins directory (actually under the addins directory at the same level as Lib) and looks for public classes that Mark nunitaddinattribute and implement the iaddin interface, then load them as plug-ins.
Nunitaddinattribute supports three optional naming parameters: type, name, and description. Both Name and description are strings to indicate the extension name and description. If the name is not provided, the class name is used by default. Type can be a combination of one or extensiontype:
[Flags]public enum ExtensionType{Core=1,Client=2,Gui=4}
If the type is not provided, the default value is extensiontype. Core.
Each plug-in must implement iaddin:
public interface IAddin{bool Install( IExtensionHost host );}
This install method will be called by the host marked by it. The plug-in should check whether necessary extension points are available and install itself. If the installation is successful, true is returned, and false is returned if the installation fails. This method is called only once when each extended Host and a new test application domain are loaded.
The install method uses the iextensionhost interface to locate the extension point:
public interface IExtensionHost{ IExtensionPoint[] ExtensionPoints { get; }IExtensionPoint GetExtensionPoint( string name );ExtensionType ExtensionTypes { get; }}
The extensionpoints attribute returns an array of all extension points required by these extensions. The extensiontypes attribute returns the identifier of the extended type supported by the current host. For example, the GUI extension is only loaded by the GUI host. Currently, the abstract class extensionhost inherited from iextensionhost implements these methods, and only coreextensions inherits from extensionhost. Therefore, only core type extensions are supported currently.
Most plug-ins only use the getextensionpoint method to obtain an interface for a specific extension point. The iextensionpoint is defined as follows:
public interface IExtensionPoint{string Name { get; }IExtensionHost Host { get; }void Install( object extension );void Remove( object extension );}
Most plug-ins only call the install method. It passes in an extension object to the extension point to be installed. In general, once installed, the extension does not have to be removed, but it is still provided just in case. The abstract class extensionpoint inherits this interface and implements these methods. It is inherited by suitebuilders, testcasebuilders, testdecorators, testcaseproviders, datapointproviders, and eventlisteners. These are the actual extension points.
In 2.5, another interface, iextensionpoint2 inherited from iextensionpoint, is introduced, which allows you to set the sequence of calls from the same extension point to other extensions:
public interface IExtensionPoint2 : IExtensionPoint{void Install( object extension, int priority );}
In version 2.5, only the testdecorators and datapointproviders extension points implement this interface.
For different extension points, the input object should inherit one or more different interfaces.
1, suitebuilders (nunit 2.4)
Suitebuilder is a plug-in that constructs a class as a test class. Nunit itself uses a suitebuilder to identify and construct a test class.
In the plug-in, we can use the host name to obtain the extension point object:
IExtensionPoint suiteBuilders = host.GetExtensionPoint( "SuiteBuilders" );
If the extension point is implemented, the extension object passed to the install method must implement the isuitebuilder interface:
public interface ISuiteBuilder{bool CanBuildFrom( Type type );Test BuildFrom( Type type );}
Canbuilderfrom should return true. If builder can build a test class from a specified type, it usually checks the type and its features. Buildfrom should return a test class containing the test method. If the test class cannot be constructed, null is returned.
2, testcasebuilders (nunit 2.4)
Testcasebuilders creates a test based on the method. Nunit uses several testcasebuilders internally to create various test methods.
Use the following code in the plug-in to obtain the extension point object:
IExtensionPoint testCaseBuilders = host.GetExtensionPoint( "TestCaseBuilders" );
The extension class of this extension point must implement one of the following two interfaces:
public interface ITestCaseBuilder{bool CanBuildFrom( MethodInfo method );Test BuildFrom( MethodInfo method );}public interface ITestCaseBuilder2 : ITestCaseBuilder{bool CanBuildFrom( MethodInfo method, Test suite );Test BuildFrom( MethodInfo method, Test suite );}
Nunit calls itestcasebuilder2 first. If it is not suitable, it calls itestcasebuilder.
Canbuildfrom should return true if the plug-in can build a test from the provided method. Some testcasebuilder plug-ins can only be applied to methods in specific test classes. The Suite parameter in the itestcasebuilder2 interface is used to make this decision. The buildfrom method should return the input parameter build test method. If the input method is unavailable, return null.
3, testdecorators (nunit 2.4)
Testdecorators can modify the test generated by the build.
The extension object can be obtained using the following code:
IExtensionPoint testDecorators = host.GetExtensionPoint( "TestDecorators" );
The extension object passed to install implements the following interfaces:
public interface ITestDecorator{Test Decorate( Test test, MemberInfo member );}
This decorate method can be used to: do nothing and return directly; modify the properties of the test object and then return; discard the test object or integrate it into the new object.
According to the requirements of the decorator, it may run before or after other decorator. The decorator can use the install method that is overloaded to input a priority identifier. The value ranges from 1 to 9, and the smaller the value, the higher the level. The following values can be called when used:
- Decoratorpriority. Default = 0
- Decoratorpriority. First = 1
- Decoratorpriority. Normal = 5
- Decoratorpriority. Last = 9
4, testcaseproviders (nunit 2.5)
Testcaseproviders is used together with a test with parameters to create a test case when a test call with parameters is performed.
The extension object can be obtained using the following code:
IExtensionPoint listeners = host.GetExtensionPoint( "ParameterProviders" );
The object passed to the install method should implement one of the following two interfaces:
public interface ITestCaseProvider{bool HasTestCasesFor( MethodInfo method );IEnumerable GetTestCasesFor( MethodInfo method );}public interface ITestCaseProvider2 : ITestCaseProvider{bool HasTestCasesFor( MethodInfo method, Test suite );IEnumerable GetTestCasesFor( MethodInfo method, Test suite );}
If 2 is not suitable, call interface 1.
HastestcasesforReturns true. If the provider provides a test case for the given method. If the provider is only applied in a specific test, it checks the suite parameter to determine whether to return true or false.
The getparametersfor method should return a series of independent tests. Each test is represented by an array of parameterset objects or parameters or custom objects that contain the following attributes:
- Arguments
- Runstate
- Notrunreason
- Expectedexceptiontype
- Expectedexceptionname
- Expectedexceptionmessage
- Result
- Description
- Testname
The parameterset class also provides these attributes for calling.
Note:
A. If you implement two interfaces, most providers use one of them to represent the other.
B. If the provider wants to use the data of the test class, use itestcaseprovider2 to ensure that it can call the parameters during the test class constructor.
C. The provider that obtains data from outside the test class only calls itestcaseprovider.
D, itestcaseprovider2 is added in version 2.5.1.
5, datapointproviders (nunit 2.5)
Datapointproviders provides data for the test method with parameters in an independent manner.
Use the following code to obtain the extension object:
IExtensionPoint listeners = host.GetExtensionPoint( "DataPointProviders" );
The extension object passed to the install method implements one of the following two interfaces:
public interface IDataPointProvider{bool HasDataFor( ParameterInfo parameter );IEnumerable GetDataFor( ParameterInfo parameter );}public interface IDataPointProvider2 : IDatapointProvider{bool HasDataFor( ParameterInfo parameter, Test parentSuite );IEnumerable GetDataFor( ParameterInfo parameter, Test parentSuite );}
Still taking priority 2.
If the provider can provide data for the specified parameter, hasdatafor returns true. If it is called by a specific test, it should check the provided parameters, associated methods, and provided parentsuite parameters. Getdatafor returns a series of independent data for running the test.
Notes in itestcaseprovider also apply to idatapointprovider.
6, eventlisteners (nunit 2.4.4)
Eventlisteners is used to respond to events that occur during the test and is usually used to record information. The call and test operations of this event listener are asynchronous and will not affect the actual operation.
The extension point object can be obtained in the following ways:
IExtensionPoint listeners = host.GetExtensionPoint( "EventListeners" );
The extension object passed to install must implement the following interfaces:
public interface EventListener{void RunStarted( string name, int testCount );void RunFinished( TestResult result );void RunFinished( Exception exception );void TestStarted(TestName testName);void TestFinished(TestResult result);void SuiteStarted(TestName testName);void SuiteFinished(TestResult result);void UnhandledException( Exception exception );void TestOutput(TestOutput testOutput);}
You must provide all methods, but it can be empty.
Some extension suggestions
First of all, nunit official documentation does not recommend that you do not need to expand development now. Instead, you want developers to encourage them to join development or ask questions and suggestions. However, they still listed some suggestions:
1, relativeNunit. CoreEach version may change,Nunit. Core. InterfacesIs relatively stable. Although these two sets are not finalized, they will be easier to use in future versions only dependent on interfaces extensions. Unfortunately, nunit Code cannot be reused and it is more difficult to work. Currently, most plug-in examples are for specific versions.
2. If you put a custom feature and your plug-in into an assembly, the user test will depend on this Assembly. If the plug-in is dependent on the version, your test depends on the version. Therefore, you should place the classes to be referenced in the user test in an independent program set, especially when your extension depends on nunit. Core.
3. If vs is used, set any reference to nunit. Core or nunit. Core. interfaces to copy local to false. If you need to compile nunit by yourself, this is very important.
4. There is no way for decorators to be applied in a certain order. Nunit applies them in the order returned by reflection, which is different at different runtime.
5. Do not extend the existing extension points beyond their own requirements. I believe nunit will provide more easy-to-use extension points in the future, or provide official nunit suggestions.
An official nunit extension example is listed below.