Part 1th: http://www.cnblogs.com/cgzl/p/8283610.html
Part 2nd: http://www.cnblogs.com/cgzl/p/8287588.html
Part 3rd: http://www.cnblogs.com/cgzl/p/8438019.html
Please use the code for this project: Https://pan.baidu.com/s/1i7d8z2H
Data-driven testing
Open PlayerCharacterShould.cs
Add a few fact test methods:
[Fact] Public voidTakezerodamage () {_sut. Takedamage (0); Assert.equal ( -, _sut. Health); } [Fact] Public voidTakesmalldamage () {_sut. Takedamage (1); Assert.equal ( About, _sut. Health); } [Fact] Public voidTakemediumdamage () {_sut. Takedamage ( -); Assert.equal ( -, _sut. Health); } [Fact] Public voidTakeminimum1damage () {_sut. Takedamage (101); Assert.equal (1, _sut. Health); }
Build, Run tests. It's all pass.
Take a closer look at these 4 methods, they actually do the same thing, but the input data and expected results are different.
So we should refactor this code.
Theory:
In this case, we are not using the fact attribute tag anymore, but we need to use theory.
The theory tag tells Xunit that the test method below will be executed multiple times, and each execution must provide the necessary test data for this method.
How do I add test data to it? The first thing to do is to add a parameter to the test method, using the parameter instead of the specific value:
[theory] Public void Takedamage (int damage, int expectedhealth) { _sut. Takedamage (damage); Assert.equal (expectedhealth, _sut. health); }
Then we need to tell Xunit where the parameters of this test method come from.
1. The simplest approach is to use the inlinedata attribute tag:
[theory] [Inlinedata (0)] [Inlinedata (1)] [Inlinedata (a)] [Inlinedata (101, 1)] Public void Takedamage (intint expectedhealth) { _sut. Takedamage (damage); Assert.equal (Expectedhealth, _sut. health); }
I added four sets of test data, each of which corresponds to two parameters of the test method in order. (The Inlinedata parameter type is params object[])
Then build, view the test Explorer:
Will find that there are more than 4 tests, respectively, corresponding to the 4 inlinedata.
Run Tests, will pass.
You can now delete the four fact test methods.
Although Inlinedata is convenient to use, in some situations it is not as flexible as you should see the code inside the NonPlayerCharacterShould.cs. Cancel the comment inside:
namespacegame.tests{ Public classnonplayercharactershould {[Theory] [Inlinedata (0, -)] [Inlinedata (1, About)] [Inlinedata ( -, -)] [Inlinedata (101,1)] Public voidTakedamage (intDamageintexpectedhealth) {nonplayercharacter sut=NewNonplayercharacter (); Sut. Takedamage (damage); Assert.equal (Expectedhealth, SUT. Health); } }}
First build, Run Tests, all pass.
The four sets of parameters for this theory are the same as above.
2. To share these sets of test data, you can use the MemberData property label to first create a class InternalHealthDamageTestData.cs:
namespacegame.tests{ Public classInternalhealthdamagetestdata {Private Static ReadOnlylist<Object[]> Data =Newlist<Object[]> { New Object[] {0, -}, New Object[] {1, About}, New Object[] { -, -}, New Object[] {101,1} }; Public Staticienumerable<Object[]> TestData =Data; }}
The data in this is the same as the previous four sets of data.
Then modify the code inside the nonplayercharactershould to remove the Inlinedata:
namespace game.tests{ public class nonplayercharactershould {[theory] [memberdata (nameof (internalhealthdamaget Estdata.testdata), MemberType = typeof (Internalhealthdamagetestdata))] public void takedamage (int damage, int Expectedhealth) {nonplayercharacter sut = new Nonplayercharacter (); Sut. Takedamage (damage); Assert.equal (Expectedhealth, SUT. Health); } }}
This is changed to MemberData, its parameters are many, the first parameter is the property name of the data supply class, this property type requirements are ienumberable, so here should write "TestData", but it is best to use nameof, If you change the property name of the data class, you will get an error at compile time without causing the test to fail.
You then also need to set the MemberType property to indicate the type of the data provider class.
Clean solution, Build, you can see there are still 4 tests, Run Tests, will pass.
For Playercharactershould, this is also modified. This allows the test data to be shared.
3. external Data .
Check out the Testdata.csv in the project: the four groups of data:
0 - 1 About - - 101 1
Then create a class ExternalHealthDamageTestData.cs to remove the data from the CSV:
namespacegame.tests{ Public classExternalhealthdamagetestdata { Public Staticienumerable<Object[]>TestData {Get { string[] Csvlines = File.ReadAllLines ("Testdata.csv"); varTestcases =Newlist<Object[]>(); foreach(varCsvlineinchcsvlines) {IEnumerable<int> values = Csvline.split (','). Select (int. Parse); Object[] TestCase = values. cast<Object>(). ToArray (); Testcases.add (testCase); } returntestcases; } } }}
Modify the property labels for the nonplayercharactershould and Playercharactershould related test methods:
namespacegame.tests{ Public classnonplayercharactershould {[Theory] [MemberData (nameof (ExternalHealthdamagetestdata.testdat A), MemberType=typeof(Externalhealthdamagetestdata))] Public voidTakedamage (intDamageintexpectedhealth) {nonplayercharacter sut=NewNonplayercharacter (); Sut. Takedamage (damage); Assert.equal (Expectedhealth, SUT. Health); } }}
[theory] [MemberData (nameof (Externaltypeof(External Healthdamagetestdata)] publicvoid takedamage (intint Expectedhealth) { _sut. Takedamage (damage); Assert.equal (Expectedhealth, _sut. health); }
Build, view Test Explorer:
For any of these classes, you can only find one related test, not four Tests.
Run tests, will error:
It can't find testdata.csv because we need to change the properties of the CSV file and change it to copy always:
Then select Rebuild solution to ensure that the CSV file is copied to the correct location.
Check the test Explorer again:
At this point you will see 4 sets of Tests, Run Tests, will pass.
If you add another set of data, you still need to rebuild solution, and the new test will appear in the test Explorer.
4.Customdataattribute The Custom Data Properties tab .
Using a custom label, you can share test data between the tests case and class, and improve the readability of your tests.
Create a class HealthDamageDataAttribute.cs:
namespacegame.tests{ Public classHealthdamagedataattribute:dataattribute { Public Overrideienumerable<Object[]>GetData (MethodInfo testMethod) {yield return New Object[] {0, - }; yield return New Object[] {1, About }; yield return New Object[] { -, - }; yield return New Object[] {101,1 }; } }}
Here you need to implement Xunit's Dataattribute this abstract class.
Modify the relevant methods of Nonplayercharactershould and Playercharactershould to write the custom labels above:
namespace game.tests{ publicclass nonplayercharactershould { [theory] [Healthdamagedata] Public void Takedamage (intint expectedhealth) { new Nonplayercharacter (); Sut. Takedamage (damage); Assert.equal (Expectedhealth, SUT. Health); }}}
Build, and then test Explorer can still see four sets of tests, and if you want to add a set of tests again, just build again.
The test will also pass.
The same custom tags can be used to integrate external data, this is very simple, you write it yourself.
This is the end of the Xunit profile, if you want to know more about it, look at the official documentation.
Unit test for. NET core programs using Xunit (4)