Я хотел бы сообщить о них до их запуска и иметь возможность запускать отдельные тесты с помощью сценариев оболочки без управления категориями. У нас есть неуправляемый код, который может оставить процесс в плохом состоянии, и иногда с удовольствием запускает каждый тест отдельно для запуска nunit-console.Может ли nunit-console перечислить все тестовые имена в тестовом устройстве?
ответ
nunit-console по-прежнему не поддерживает этот вариант. Однако довольно просто получить список тестовых примеров с использованием отражения. На базовом уровне вам нужен список всех методов public
любых public class
с соответствующими атрибутами [Test]/[TestFixture]
. В зависимости от того, как ваши тесты структурированы, вам может потребоваться дополнительная фильтрация, например, для удаления любых тестов, отмеченных атрибутами [Ignore]
, или для рассмотрения методов тестирования в базовых классах.
На базовом уровне, код будет выглядеть примерно так:
// 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);
}
}
Очевидно, что вы были бы в состоянии упорядочить это немного, если вы только хотели методы испытаний от конкретного TestFixture
.
Как уже было сказано в комментариях, это становится немного сложнее, если вам нужно обратить внимание на другие атрибуты NUnit, такие как TestCase
и TestCaseSource
. Я изменил код ниже, чтобы поддержать некоторые функциональные возможности этих атрибутов.
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);
}
Если посмотреть через код выше, вы можете заметить, что я перевалено функциональность, где TestCaseSource
для испытаний является строкой, содержащим названием свойства/метода/поля. Вы также заметите, что в то время как есть код, он по-прежнему довольно простой код, поэтому его можно было бы легко расширить, если вы использовали альтернативную версию TestCaseSource, или если есть другие атрибуты NUnit, которые вы используете, что я не удовлетворяют.
Было бы достаточно просто добавить счетчик выше, чтобы у вас был уровень комфорта, при котором было напечатано столько же тестов, сколько количества тестов, которые будут выполняться с помощью nunit-console.
Это позволит получить основы, но если вы используете некоторые из более продвинутых атрибутов, которые могут автоматически генерировать тесты с разных входов, вам не повезло! –
@SebastianGood Я добавил поддержку TestCase + некоторых подстановок TestCaseSource к вышеперечисленному. Расширение кода для обработки других параметров TestCaseSource (или других атрибутов, которые я не нашел) должно быть простым, если вы используете альтернативные, но я оставлю это как упражнение для читателя *. – forsvarir
Вам также необходимо рассмотреть случаи, когда классы тестов наследуют (абстрактные) базовые классы с этими атрибутами. Затем счет нужно настроить для одновременного использования одних и тех же методов тестирования, – WebDancer
В настоящее время имеется опция командной строки --explore
, которая может использоваться для перечисления всех тестовых примеров без проведения тестов. Более конкретно
nunit3-console.exe MyProject.dll --explore
Для получения дополнительной информации: https://github.com/nunit/docs/wiki/Console-Command-Line#description
'NUnit-консоль MyAssembly.dll/labels' покажет все тесты, как они работают, но я прав, полагая, что то, что вы хотите получить, что , а затем запросить пользователя (или добавить их в файл '/ runlist =')? И в чем же причина, по которой вы не хотите использовать категории? – ClickRick
Мы хотим их раньше времени, правильно. Ключевым моментом здесь было то, что мы хотели запускать их по одному, т. Е. Запускать nunit-консоль снова и снова, один раз за тест. Мы изменили компоненты таким образом, что нам действительно не нужно это делать больше, но я все еще удивлен тем, что не вижу ответа на это. –
Если это все еще проблема для вас, у меня возникнет соблазн изучить их класс EventListener (см. Http://imistaken.blogspot.co.uk/2009/03/nunit-extensions-adding-logic-at-run .html для примера), чтобы увидеть, можете ли вы получить список таким образом, но это будет полагаться на возможность подавить фактический запуск тестов в этот момент, и это то, что я не знаю, не попробовав его. – ClickRick