Tôi muốn báo cáo chúng trước khi chúng chạy và có tùy chọn chạy các thử nghiệm riêng lẻ thông qua các tập lệnh shell mà không cần quản lý danh mục. Chúng tôi có một số mã không được quản lý có thể để lại quá trình ở trạng thái xấu và đôi khi rất vui khi chạy từng thử nghiệm riêng lẻ cho mỗi lần chạy trên bàn điều khiển nunit.Có thể nunit-console liệt kê tất cả các tên thử nghiệm trong một trận thi đấu không?
Trả lời
nunit-console vẫn không hỗ trợ tùy chọn này. Tuy nhiên nó khá đơn giản để có được một danh sách các trường hợp thử nghiệm sử dụng sự phản chiếu. Ở cấp độ rất cơ bản, bạn muốn có danh sách tất cả các phương pháp public
của bất kỳ public class
nào với thuộc tính [Test]/[TestFixture]
thích hợp. Tùy thuộc vào cách kiểm tra của bạn được cấu trúc, bạn có thể cần phải thực hiện lọc bổ sung, chẳng hạn như để loại bỏ bất kỳ thử nghiệm nào được đánh dấu với thuộc tính [Ignore]
hoặc để xem xét các phương pháp thử nghiệm trong các lớp cơ sở.
Ở mức độ cơ bản, mã sẽ giống như thế này:
// Load the assembly containing your fixtures
Assembly a = Assembly.LoadFrom(assemblyName);
// Foreach public class that is a TestFixture and not Ignored
foreach (var c in a.GetTypes()
.Where(x=>x.IsPublic
&& (x.GetCustomAttributes(typeof(NUnit.Framework.TestFixtureAttribute)).Count() > 0)
&& (x.GetCustomAttributes(typeof(NUnit.Framework.IgnoreAttribute)).Count() ==0)))
{
// For each public method that is a Test and not Ignored
foreach (var m in c.GetMethods()
.Where(x=>x.IsPublic
&& (x.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute)).Count() > 0)
&& (x.GetCustomAttributes(typeof(NUnit.Framework.IgnoreAttribute)).Count() ==0)))
{
// Print out the test name
Console.WriteLine("{0}.{1}", c.ToString(), m.Name);
// Alternately, print out the command line to run test case using nunit-console
//Console.WriteLine("nunit-console /run:{0}.{1} {2}", c.ToString(), m.Name, assemblyName);
}
}
Rõ ràng bạn muốn có thể sắp xếp này một chút nếu bạn chỉ muốn các phương pháp kiểm tra từ một đặc biệt TestFixture
.
Như đã nói trong phần nhận xét, điều này sẽ phức tạp hơn một chút nếu bạn cần chú ý đến các thuộc tính NUnit khác, chẳng hạn như TestCase
và TestCaseSource
. Tôi đã sửa đổi mã bên dưới để hỗ trợ một số chức năng của các thuộc tính này.
static void PrintTestNames(string assemblyName) {
Assembly assembly = Assembly.LoadFrom(assemblyName);
foreach (var fixture in assembly.GetTypes().Where(x => x.IsPublic
&& (x.GetCustomAttributes(typeof(TestFixtureAttribute)).Count() > 0)
&& (x.GetCustomAttributes(typeof(IgnoreAttribute)).Count() == 0))) {
foreach(var method in fixture.GetMethods().Where(x=>x.IsPublic
&& (x.GetCustomAttributes(typeof(IgnoreAttribute)).Count() == 0)
&& ((x.GetCustomAttributes(typeof(TestAttribute)).Count() > 0)
|| (x.GetCustomAttributes(typeof(TestCaseAttribute)).Count() > 0)
|| (x.GetCustomAttributes(typeof(TestCaseSourceAttribute)).Count() > 0))
)) {
var testAttributes = method.GetCustomAttributes(typeof(TestAttribute)) as IEnumerable<TestAttribute>;
var caseAttributes = method.GetCustomAttributes(typeof(TestCaseAttribute)) as IEnumerable<TestCaseAttribute>;
var caseSourceAttributes = method.GetCustomAttributes(typeof(TestCaseSourceAttribute)) as IEnumerable<TestCaseSourceAttribute>;
if (caseAttributes.Count() > 0) {
foreach(var testCase in caseAttributes) {
if (!string.IsNullOrEmpty(testCase.TestName)) {
PrintTestName(fixture.ToString(), testCase.TestName);
}
else {
string arguments = ExtractArguments(testCase.Arguments);
PrintTestName(fixture.ToString(), method.Name + arguments);
}
}
}
else if (caseSourceAttributes.Count() > 0) {
foreach (var testCase in caseSourceAttributes) {
var sourceName = testCase.SourceName;
if (!string.IsNullOrEmpty(sourceName)) {
var staticMember = fixture.GetField(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var instanceMember = fixture.GetField(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var staticMethodMember = fixture.GetMethod(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var instanceMethodMember = fixture.GetMethod(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var staticPropMember = fixture.GetProperty(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var instancePropMember = fixture.GetProperty(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
IEnumerable memberValues;
if (null != staticMember) {
memberValues = staticMember.GetValue(null) as IEnumerable;
}
else if (null != instanceMember) {
var instance = Activator.CreateInstance(fixture);
memberValues = instanceMember.GetValue(instance) as IEnumerable;
} else if(null != staticMethodMember) {
memberValues = staticMethodMember.Invoke(null,new object [0]) as IEnumerable;
}
else if (null != instanceMethodMember) {
var instance = Activator.CreateInstance(fixture);
memberValues = instanceMethodMember.Invoke(instance, new object[0]) as IEnumerable;
}
else if (null != staticPropMember) {
memberValues = staticPropMember.GetValue(null) as IEnumerable;
}
else if (null != instancePropMember) {
var instance = Activator.CreateInstance(fixture);
memberValues = instancePropMember.GetValue(instance) as IEnumerable;
}
else {
Console.WriteLine("*** Ooops...Looks like I don't know how to get {0} for fixture {1}", sourceName, fixture.ToString());
continue;
}
foreach (var memberValue in memberValues) {
if (null != memberValue as IEnumerable) {
PrintTestName(fixture.ToString(), method.Name + ExtractArguments(memberValue as IEnumerable));
}
else {
PrintTestName(fixture.ToString(), method.Name + "(" + memberValue.ToString() + ")");
}
}
} else {
Console.WriteLine("*** Ooops...Looks like I don't know how to handle test {0} for fixture {1}", method.Name, fixture.ToString());
}
}
}
else {
PrintTestName(fixture.ToString(), method.Name);
}
}
}
}
static string ExtractArguments(IEnumerable arguments) {
string caseArgs = "(";
bool first = true;
foreach (var arg in arguments) {
if (first) first = false;
else caseArgs += ",";
caseArgs += Convert.ToString(arg);
}
return caseArgs + ")";
}
static void PrintTestName(string fixture, string testName) {
Console.WriteLine("{0}.{1}", fixture, testName);
//Console.WriteLine("nunit-console /run:{0}.{1} {2}", fixture, testName, assemblyName);
}
Nếu bạn xem xét thông qua các mã trên, bạn có thể nhận thấy rằng tôi đã xử lý chức năng nơi TestCaseSource
cho kiểm tra là một chuỗi đặt tên thuộc tính/phương pháp/lĩnh vực. Bạn cũng sẽ nhận thấy rằng trong khi có mã nhiều hơn, mã này vẫn khá đơn giản, vì vậy có thể dễ dàng mở rộng nếu bạn đang sử dụng phiên bản thay thế của TestCaseSource hoặc nếu có các thuộc tính NUnit khác bạn đang sử dụng đã không phục vụ cho. Bạn cũng có thể dễ dàng thêm một bộ đếm ở trên để bạn có mức độ thoải mái mà cùng số lượng các bài kiểm tra được in khi số lượng bài kiểm tra mà nunit-console sẽ chạy.
Điều này sẽ có được những điều cơ bản, nhưng nếu bạn sử dụng một số thuộc tính nâng cao hơn có thể tự động tạo ra các bài kiểm tra từ các đầu vào khác nhau, thì bạn sẽ không may mắn! –
@SebastianGood Tôi đã thêm hỗ trợ cho TestCase + một số hoán vị TestCaseSource vào ở trên. Việc mở rộng mã để xử lý các tùy chọn TestCaseSource khác (hoặc các thuộc tính khác mà tôi chưa tìm thấy) nên đơn giản nếu bạn đang sử dụng các thay thế, tuy nhiên tôi sẽ để nó như là một bài tập * cho người đọc *. – forsvarir
Bạn cũng cần phải xem xét các trường hợp mà các lớp thử nghiệm kế thừa từ các lớp cơ sở (trừu tượng) với các thuộc tính này. Sau đó, số cần phải được điều chỉnh để chạy cùng một phương pháp thử nghiệm nhiều lần, – WebDancer
Hiện tại có tùy chọn dòng lệnh --explore
có thể được sử dụng để liệt kê tất cả các trường hợp thử nghiệm mà không chạy thử nghiệm. Cụ thể hơn
nunit3-console.exe MyProject.dll --explore
Để biết thêm thông: https://github.com/nunit/docs/wiki/Console-Command-Line#description
'nunit-console MyAssembly.dll/labels' sẽ hiển thị tất cả các bài kiểm tra khi họ chạy, nhưng tôi phải trong suy nghĩ rằng những gì bạn muốn là để có được điều đó liệt kê trước và sau đó nhắc người dùng (hoặc thêm chúng vào một tệp '/ runlist =')? Và lý do không muốn sử dụng danh mục là gì? – ClickRick
Chúng tôi muốn chúng trước thời hạn, chính xác. Chìa khóa ở đây là chúng tôi muốn chạy chúng một lần, tức là chạy nunit-giao diện điều khiển chính nó hơn và hơn nữa, một lần cho mỗi thử nghiệm. Chúng tôi đã thay đổi các thành phần như vậy mà chúng tôi không thực sự cần phải làm điều này nữa, nhưng tôi vẫn rất ngạc nhiên khi không thấy câu trả lời về điều này. –
Nếu điều này vẫn còn là một vấn đề đối với bạn, tôi sẽ bị cám dỗ để xem xét sử dụng lớp EventListener của họ (xem http://imistaken.blogspot.co.uk/2009/03/nunit-extensions-adding-logic-at-run .html cho một ví dụ) để xem bạn có thể lấy danh sách theo cách đó hay không, nhưng điều đó sẽ dựa vào việc có thể ngăn chặn việc chạy thử nghiệm thực tế tại thời điểm đó, và đó là điều tôi không biết mà không thử nó. – ClickRick