โดยค่าเริ่มต้นการทดสอบแม่ชีจะรันตามตัวอักษร ไม่มีใครรู้วิธีกำหนดคำสั่งประหารชีวิต? มีแอตทริบิวต์สำหรับสิ่งนี้หรือไม่?
โดยค่าเริ่มต้นการทดสอบแม่ชีจะรันตามตัวอักษร ไม่มีใครรู้วิธีกำหนดคำสั่งประหารชีวิต? มีแอตทริบิวต์สำหรับสิ่งนี้หรือไม่?
คำตอบ:
การทดสอบหน่วยของคุณควรสามารถดำเนินการได้อย่างอิสระและเป็นเอกเทศ หากตรงตามเกณฑ์นี้คำสั่งก็ไม่สำคัญ
มีบางครั้งที่คุณจะต้องทำการทดสอบก่อน ตัวอย่างทั่วไปคือในสถานการณ์การผสานรวมแบบต่อเนื่องซึ่งการทดสอบบางอย่างทำงานนานกว่าการทดสอบอื่น ๆ เราใช้แอตทริบิวต์หมวดหมู่เพื่อให้เราสามารถเรียกใช้การทดสอบซึ่งใช้การเยาะเย้ยก่อนการทดสอบที่ใช้ฐานข้อมูล
กล่าวคือวางสิ่งนี้เมื่อเริ่มการทดสอบอย่างรวดเร็วของคุณ
[Category("QuickTests")]
ที่คุณมีการทดสอบซึ่งจะขึ้นอยู่กับสภาพแวดล้อมบางอย่างพิจารณาTestFixtureSetUpและTestFixtureTearDownคุณลักษณะที่ช่วยให้คุณวิธีการทำเครื่องหมายที่จะดำเนินการก่อนและหลังการทดสอบของคุณ
ฉันแค่ต้องการชี้ให้เห็นว่าในขณะที่ผู้ตอบส่วนใหญ่คิดว่าเป็นการทดสอบหน่วย แต่คำถามไม่ได้ระบุว่าเป็น
nUnit เป็นเครื่องมือที่ยอดเยี่ยมที่สามารถใช้ได้กับสถานการณ์การทดสอบที่หลากหลาย ฉันเห็นเหตุผลที่เหมาะสมที่ต้องการควบคุมคำสั่งทดสอบ
ในสถานการณ์เหล่านั้นฉันต้องใช้การรวมลำดับการทำงานเข้ากับชื่อการทดสอบ จะเป็นการดีที่สามารถระบุลำดับการรันโดยใช้แอตทริบิวต์
001_first_test
002_second_test
เป็นต้น?
NUnit 3.2.0 เพิ่มOrderAttribute
แล้วดู:
https://github.com/nunit/docs/wiki/Order-Attribute
ตัวอย่าง:
public class MyFixture
{
[Test, Order(1)]
public void TestA() { ... }
[Test, Order(2)]
public void TestB() { ... }
[Test]
public void TestC() { ... }
}
การต้องการให้การทดสอบทำงานตามลำดับที่เฉพาะเจาะจงไม่ได้หมายความว่าการทดสอบจะขึ้นอยู่กับกันและกัน - ฉันกำลังทำงานในโครงการ TDD ในขณะนี้และเป็น TDDer ที่ดีที่ฉันได้เยาะเย้ย / ขีดฆ่าทุกอย่าง แต่มันจะทำให้ มันอ่านง่ายขึ้นถ้าฉันสามารถระบุลำดับที่จะแสดงผลการทดสอบ- ตามหัวข้อแทนที่จะเป็นตัวอักษร จนถึงตอนนี้สิ่งเดียวที่ฉันคิดได้คือการเพิ่ม a_ b_ c_ ไปยังคลาสของคลาสเนมสเปซและวิธีการ (ไม่ดี) ฉันคิดว่าแอตทริบิวต์ [TestOrderAttribute] น่าจะดีไม่ใช่ตามกรอบอย่างเข้มงวด แต่เป็นคำใบ้เพื่อให้เราบรรลุเป้าหมายนี้
ไม่ว่าการทดสอบจะขึ้นอยู่กับลำดับหรือไม่ก็ตาม ... พวกเราบางคนต้องการควบคุมทุกสิ่งอย่างเป็นระเบียบ
การทดสอบหน่วยมักจะสร้างขึ้นตามลำดับความซับซ้อน เหตุใดจึงไม่ควรเรียกใช้ตามลำดับความซับซ้อนหรือลำดับที่สร้างขึ้น
โดยส่วนตัวแล้วฉันชอบที่จะเห็นการทดสอบดำเนินไปตามลำดับที่ฉันสร้างขึ้น ใน TDD การทดสอบต่อเนื่องแต่ละครั้งจะมีความซับซ้อนมากขึ้นและต้องใช้เวลามากขึ้นในการดำเนินการ ฉันอยากจะเห็นว่าการทดสอบที่ง่ายกว่านั้นล้มเหลวก่อนเพราะมันจะเป็นตัวบ่งชี้ที่ดีกว่าว่าสาเหตุของความล้มเหลว
แต่ฉันยังสามารถเห็นประโยชน์ของการเรียกใช้แบบสุ่มโดยเฉพาะอย่างยิ่งหากคุณต้องการทดสอบว่าการทดสอบของคุณไม่มีการพึ่งพาการทดสอบอื่น ๆ แล้วการเพิ่มตัวเลือกในการทดสอบนักวิ่งเป็น "Run Tests Randomly until Stopped" เป็นอย่างไร?
ฉันกำลังทดสอบกับ Selenium บนเว็บไซต์ที่ค่อนข้างซับซ้อนและชุดการทดสอบทั้งหมดสามารถใช้งานได้นานกว่าครึ่งชั่วโมงและฉันยังไม่ครอบคลุมแอปพลิเคชันทั้งหมด หากฉันต้องตรวจสอบให้แน่ใจว่ากรอกแบบฟอร์มก่อนหน้านี้ทั้งหมดอย่างถูกต้องสำหรับการทดสอบแต่ละครั้งสิ่งนี้จะเพิ่มเวลาให้กับการทดสอบโดยรวมไม่ใช่เพียงเล็กน้อย หากมีค่าใช้จ่ายในการดำเนินการทดสอบมากเกินไปผู้คนจะไม่เรียกใช้บ่อยเท่าที่ควร
ดังนั้นฉันจึงเรียงลำดับและขึ้นอยู่กับการทดสอบก่อนหน้านี้ว่ามีกล่องข้อความและเสร็จสมบูรณ์แล้ว ฉันใช้ Assert.Ignore () เมื่อเงื่อนไขเบื้องต้นไม่ถูกต้อง แต่ฉันจำเป็นต้องให้เงื่อนไขเหล่านั้นทำงานตามลำดับ
ฉันชอบคำตอบก่อนหน้านี้มาก
ฉันเปลี่ยนแปลงเล็กน้อยเพื่อให้สามารถใช้แอตทริบิวต์เพื่อกำหนดช่วงการสั่งซื้อ:
namespace SmiMobile.Web.Selenium.Tests
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
public class OrderedTestAttribute : Attribute
{
public int Order { get; set; }
public OrderedTestAttribute(int order)
{
Order = order;
}
}
public class TestStructure
{
public Action Test;
}
class Int
{
public int I;
}
[TestFixture]
public class ControllingTestOrder
{
private static readonly Int MyInt = new Int();
[TestFixtureSetUp]
public void SetUp()
{
MyInt.I = 0;
}
[OrderedTest(0)]
public void Test0()
{
Console.WriteLine("This is test zero");
Assert.That(MyInt.I, Is.EqualTo(0));
}
[OrderedTest(2)]
public void ATest0()
{
Console.WriteLine("This is test two");
MyInt.I++; Assert.That(MyInt.I, Is.EqualTo(2));
}
[OrderedTest(1)]
public void BTest0()
{
Console.WriteLine("This is test one");
MyInt.I++; Assert.That(MyInt.I, Is.EqualTo(1));
}
[OrderedTest(3)]
public void AAA()
{
Console.WriteLine("This is test three");
MyInt.I++; Assert.That(MyInt.I, Is.EqualTo(3));
}
[TestCaseSource(sourceName: "TestSource")]
public void MyTest(TestStructure test)
{
test.Test();
}
public IEnumerable<TestCaseData> TestSource
{
get
{
var assembly =Assembly.GetExecutingAssembly();
Dictionary<int, List<MethodInfo>> methods = assembly
.GetTypes()
.SelectMany(x => x.GetMethods())
.Where(y => y.GetCustomAttributes().OfType<OrderedTestAttribute>().Any())
.GroupBy(z => z.GetCustomAttribute<OrderedTestAttribute>().Order)
.ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());
foreach (var order in methods.Keys.OrderBy(x => x))
{
foreach (var methodInfo in methods[order])
{
MethodInfo info = methodInfo;
yield return new TestCaseData(
new TestStructure
{
Test = () =>
{
object classInstance = Activator.CreateInstance(info.DeclaringType, null);
info.Invoke(classInstance, null);
}
}).SetName(methodInfo.Name);
}
}
}
}
}
}
OrderedTest
ไม่รองรับใน NUnit 3 อีกต่อไป
ฉันรู้ว่านี่เป็นโพสต์ที่ค่อนข้างเก่า แต่นี่เป็นอีกวิธีหนึ่งในการรักษาการทดสอบของคุณให้เป็นระเบียบโดยที่ไม่ทำให้ชื่อการทดสอบน่าอึดอัด ด้วยการใช้แอตทริบิวต์ TestCaseSource และให้ออบเจ็กต์ที่คุณส่งผ่านมีผู้รับมอบสิทธิ์ (Action) คุณไม่เพียง แต่สามารถควบคุมคำสั่งได้ทั้งหมด แต่ยังตั้งชื่อการทดสอบว่ามันคืออะไร
วิธีนี้ใช้ได้ผลเนื่องจากตามเอกสารประกอบรายการในคอลเล็กชันที่ส่งคืนจากแหล่งทดสอบจะดำเนินการตามลำดับที่ระบุไว้เสมอ
นี่คือตัวอย่างจากการนำเสนอที่ฉันจะให้ในวันพรุ่งนี้:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace NUnitTest
{
public class TestStructure
{
public Action Test;
}
class Int
{
public int I;
}
[TestFixture]
public class ControllingTestOrder
{
private static readonly Int MyInt= new Int();
[TestFixtureSetUp]
public void SetUp()
{
MyInt.I = 0;
}
[TestCaseSource(sourceName: "TestSource")]
public void MyTest(TestStructure test)
{
test.Test();
}
public IEnumerable<TestCaseData> TestSource
{
get
{
yield return new TestCaseData(
new TestStructure
{
Test = () =>
{
Console.WriteLine("This is test one");
MyInt.I++; Assert.That(MyInt.I, Is.EqualTo(1));
}
}).SetName(@"Test One");
yield return new TestCaseData(
new TestStructure
{
Test = () =>
{
Console.WriteLine("This is test two");
MyInt.I++; Assert.That(MyInt.I, Is.EqualTo(2));
}
}).SetName(@"Test Two");
yield return new TestCaseData(
new TestStructure
{
Test = () =>
{
Console.WriteLine("This is test three");
MyInt.I++; Assert.That(MyInt.I, Is.EqualTo(3));
}
}).SetName(@"Test Three");
}
}
}
}
TestCaseSource
เป็นวิธีเรียกใช้การทดสอบตามลำดับถือเป็นความอัจฉริยะ ทำได้ดี. ฉันได้ใช้แนวทางนี้ร่วมกับแนวทางด้านล่างและได้เพิ่มการปรับเปลี่ยนเพิ่มเติมเล็กน้อยเพื่อให้ใช้งานได้ง่ายขึ้น ดูลิงก์ในคำตอบของฉันสำหรับข้อมูลเพิ่มเติม แต่แนวคิดพื้นฐานมาจากคำตอบที่ยอดเยี่ยมนี้!
TestCaseSource
ต้องเป็นแบบคงที่ซึ่งขัดขวางการใช้รูปแบบ แย่จัง.
TestCaseSource
ต้องเป็นวัตถุคงที่ใน NUnit 3 ไม่เช่นนั้นการทดสอบจะไม่ดำเนินการ และคุณไม่สามารถสร้างวัตถุแบบไดนามิกภายในวัตถุคงที่ นั่นเป็นเหตุผลที่มันใช้ไม่ได้ใน
ฉันกำลังทำงานกับกรณีทดสอบ UI แบบ end-to-end ของ Selenium WebDriver ที่เขียนด้วยภาษา C # ซึ่งทำงานโดยใช้ NUnit framework (ไม่ใช่กรณีหน่วยเช่นนี้)
การทดสอบ UI เหล่านี้ขึ้นอยู่กับลำดับการดำเนินการอย่างแน่นอนเนื่องจากการทดสอบอื่น ๆ จำเป็นต้องเพิ่มข้อมูลบางส่วนเป็นเงื่อนไขเบื้องต้น (เป็นไปไม่ได้ที่จะทำตามขั้นตอนในการทดสอบทุกครั้ง)
ตอนนี้หลังจากเพิ่มกรณีทดสอบที่ 10 แล้วฉันเห็นว่า NUnit ต้องการเรียกใช้ตามลำดับนี้: Test_1 Test_10 Test_2 Test_3 ..
ดังนั้นฉันเดาว่าฉันต้องเรียงชื่อเคสทดสอบตามตัวอักษรในตอนนี้ แต่จะเป็นการดีที่จะเพิ่มคุณสมบัติเล็ก ๆ ในการควบคุมคำสั่งการดำเนินการลงใน NUnit
โดยปกติการทดสอบหน่วยควรเป็นอิสระ แต่ถ้าคุณต้องคุณสามารถตั้งชื่อวิธีการของคุณตามลำดับตัวอักษรเช่น:
[Test]
public void Add_Users(){}
[Test]
public void Add_UsersB(){}
[Test]
public void Process_Users(){}
หรือจะทำ ..
private void Add_Users(){}
private void Add_UsersB(){}
[Test]
public void Process_Users()
{
Add_Users();
Add_UsersB();
// more code
}
a_
b_
t1_
, t2_
แทนหรืออาศัยง่ายที่จะพลาดตัวอักษรต่อท้าย
มีเหตุผลที่ดีมากในการใช้กลไกการสั่งซื้อการทดสอบ การทดสอบส่วนใหญ่ของฉันใช้แนวทางปฏิบัติที่ดีเช่นการตั้งค่า / การฉีกขาด คนอื่น ๆ ต้องการการตั้งค่าข้อมูลจำนวนมากซึ่งสามารถใช้ทดสอบคุณสมบัติต่างๆได้ จนถึงตอนนี้ฉันได้ใช้การทดสอบขนาดใหญ่เพื่อจัดการกับการทดสอบการรวม (Selenium Webdriver) เหล่านี้ อย่างไรก็ตามฉันคิดว่าโพสต์ที่แนะนำข้างต้นใน https://github.com/nunit/docs/wiki/Order-Attributeมีประโยชน์มาก นี่คือตัวอย่างว่าทำไมการสั่งซื้อจึงมีคุณค่ามาก:
เวลารอ 10 นาทีนี้ทำให้ชุดทดสอบช้าลง เมื่อคุณทวีคูณความล่าช้าในการแคชที่คล้ายกันในการทดสอบจำนวนมากจะใช้เวลามาก การสั่งซื้อการทดสอบอาจช่วยให้การตั้งค่าข้อมูลสามารถทำได้โดยเป็น "การทดสอบ" ที่จุดเริ่มต้นของชุดทดสอบโดยการทดสอบที่อาศัยแคชเพื่อหยุดการทำงานจะถูกดำเนินการในตอนท้ายของการทดสอบ
คำถามนี้เก่ามากแล้วในตอนนี้ แต่สำหรับผู้ที่สามารถเข้าถึงสิ่งนี้ได้จากการค้นหาฉันได้รับคำตอบที่ยอดเยี่ยมจาก user3275462 และ PvtVandals / Rico และเพิ่มลงในที่เก็บ GitHubพร้อมกับการอัปเดตของฉันเอง ฉันยังสร้างบล็อกโพสต์ที่เกี่ยวข้องพร้อมข้อมูลเพิ่มเติมที่คุณสามารถดูข้อมูลเพิ่มเติมได้
หวังว่านี่จะเป็นประโยชน์สำหรับคุณทุกคน นอกจากนี้ฉันมักชอบใช้แอตทริบิวต์ Category เพื่อแยกความแตกต่างของการทดสอบการรวมหรือการทดสอบแบบ end-to-end จากการทดสอบหน่วยจริงของฉัน คนอื่น ๆ ชี้ให้เห็นว่าการทดสอบหน่วยไม่ควรมีการพึ่งพาคำสั่ง แต่ประเภทการทดสอบอื่น ๆ มักจะทำดังนั้นจึงเป็นวิธีที่ดีในการเรียกใช้ประเภทการทดสอบที่คุณต้องการเท่านั้นและยังสั่งซื้อการทดสอบแบบ end-to-end เหล่านั้น
ฉันแปลกใจที่ชุมชน NUnit ไม่ได้คิดอะไรขึ้นมาดังนั้นฉันจึงไปสร้างสิ่งนี้ด้วยตัวเอง
ฉันกำลังพัฒนาไลบรารีโอเพนซอร์สที่ให้คุณสั่งการทดสอบด้วย NUnit คุณสามารถสั่งซื้ออุปกรณ์ทดสอบและสั่งซื้อ "ข้อกำหนดการทดสอบที่สั่งซื้อ" ได้
ห้องสมุดมีคุณสมบัติดังต่อไปนี้:
ไลบรารีได้รับแรงบันดาลใจจากวิธีที่ MSTest ทดสอบการสั่งซื้อด้วย.orderedtest
ไฟล์ โปรดดูตัวอย่างด้านล่าง
[OrderedTestFixture]
public sealed class MyOrderedTestFixture : TestOrderingSpecification {
protected override void DefineTestOrdering() {
TestFixture<Fixture1>();
OrderedTestSpecification<MyOtherOrderedTestFixture>();
TestFixture<Fixture2>();
TestFixture<Fixture3>();
}
protected override bool ContinueOnError => false; // Or true, if you want to continue even if a child test fails
}
หากคุณกำลังใช้[TestCase]
อาร์กิวเมนต์TestName
จะระบุชื่อสำหรับการทดสอบ
หากไม่ได้ระบุชื่อจะถูกสร้างขึ้นตามชื่อเมธอดและอาร์กิวเมนต์ที่ระบุ
คุณสามารถควบคุมลำดับของการดำเนินการทดสอบได้ตามที่ระบุด้านล่าง:
[Test]
[TestCase("value1", TestName = "ExpressionTest_1")]
[TestCase("value2", TestName = "ExpressionTest_2")]
[TestCase("value3", TestName = "ExpressionTest_3")]
public void ExpressionTest(string v)
{
//do your stuff
}
ที่นี่ฉันใช้"ExpressionTest"
คำต่อท้ายชื่อวิธีกับตัวเลข
คุณสามารถใช้ชื่อใดก็ได้ที่เรียงตามตัวอักษรโปรดดูที่TestCase Attribute
คุณไม่ควรขึ้นอยู่กับลำดับที่กรอบการทดสอบเลือกการทดสอบเพื่อดำเนินการการทดสอบควรแยกและเป็นอิสระ ในนั้นพวกเขาไม่ควรขึ้นอยู่กับการทดสอบอื่น ๆ ที่กำหนดขั้นตอนสำหรับพวกเขาหรือทำความสะอาดหลังจากนั้น นอกจากนี้ควรให้ผลลัพธ์เดียวกันโดยไม่คำนึงถึงลำดับของการดำเนินการทดสอบ (สำหรับภาพรวมของมทส.)
ฉันทำ Googling นิดหน่อย ตามปกติบางคนใช้กลอุบายลับๆล่อๆ (แทนที่จะแก้ปัญหาการทดสอบ / การออกแบบที่ซ่อนอยู่
ดูเพิ่มเติม: ลักษณะของการทดสอบที่ดี
ในกรณีที่ใช้TestCaseSource
คีย์คือoverride string ToString
วิธีการทำงาน:
สมมติว่าคุณมีคลาส TestCase
public class TestCase
{
public string Name { get; set; }
public int Input { get; set; }
public int Expected { get; set; }
}
และรายการ TestCases:
private static IEnumerable<TestCase> TestSource()
{
return new List<TestCase>
{
new TestCase()
{
Name = "Test 1",
Input = 2,
Expected = 4
},
new TestCase()
{
Name = "Test 2",
Input = 4,
Expected = 16
},
new TestCase()
{
Name = "Test 3",
Input = 10,
Expected = 100
}
};
}
ตอนนี้ให้ใช้วิธีทดสอบและดูว่าเกิดอะไรขึ้น:
[TestCaseSource(nameof(TestSource))]
public void MethodXTest(TestCase testCase)
{
var x = Power(testCase.Input);
x.ShouldBe(testCase.Expected);
}
สิ่งนี้จะไม่ทดสอบตามลำดับและผลลัพธ์จะเป็นดังนี้:
ดังนั้นถ้าเราเพิ่ม override string ToString
ในชั้นเรียนของเราเช่น:
public class TestCase
{
public string Name { get; set; }
public int Input { get; set; }
public int Expected { get; set; }
public override string ToString()
{
return Name;
}
}
ผลลัพธ์จะเปลี่ยนไปและเราได้ลำดับและชื่อการทดสอบเช่น:
บันทึก: