Permalink
Browse files

Merge pull request #24 from mexx/skipped-tests

Skip cases
  • Loading branch information...
2 parents 6ea34b6 + 43a088c commit c46730fec215a8efb5b35ef2d3469475f554f0df @plioi plioi committed Nov 30, 2013
@@ -64,6 +64,10 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Shuffle\CustomConvention.cs" />
<Compile Include="Shuffle\OrderTests.cs" />
+ <Compile Include="Skipped\SkipAttribute.cs" />
+ <Compile Include="Skipped\SkipClassTests.cs" />
+ <Compile Include="Skipped\CustomConvention.cs" />
+ <Compile Include="Skipped\SkipMethodTests.cs" />
<Compile Include="StringBuilderExtensions.cs" />
<Compile Include="xUnitStyle\CalculatorTests.cs" />
<Compile Include="xUnitStyle\CustomConvention.cs" />
@@ -0,0 +1,25 @@
+using System;
+using Fixie.Conventions;
+
+namespace Fixie.Samples.Skipped
+{
+ public class CustomConvention : Convention
+ {
+ public CustomConvention()
+ {
+ Classes
+ .Where(type => type.IsInNamespace(GetType().Namespace))
+ .NameEndsWith("Tests");
+
+ Methods
+ .Where(method => method.IsVoid());
+
+ CaseExecution
+ .Skip(@case => @case.Method.HasOrInherits<SkipAttribute>() || @case.Method.DeclaringType.HasOrInherits<SkipAttribute>());
+
+ ClassExecution
+ .CreateInstancePerTestClass()
+ .SortCases((caseA, caseB) => String.Compare(caseA.Name, caseB.Name, StringComparison.Ordinal));
+ }
+ }
+}
@@ -0,0 +1,7 @@
+using System;
+
+namespace Fixie.Samples.Skipped
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
+ public class SkipAttribute : Attribute { }
+}
@@ -0,0 +1,13 @@
+using System;
+
+namespace Fixie.Samples.Skipped
+{
+ [Skip]
+ public class SkipClassTests
+ {
+ public void ShouldNotBeCalled()
+ {
+ throw new Exception("This test should be skipped.");
+ }
+ }
+}
@@ -0,0 +1,47 @@
+using System;
+using System.Text;
+using Should;
+
+namespace Fixie.Samples.Skipped
+{
+ public class SkipMethodTests : IDisposable
+ {
+ Calculator calculator;
+ readonly StringBuilder log;
+
+ public SkipMethodTests()
+ {
+ calculator = new Calculator();
+ log = new StringBuilder();
+ log.WhereAmI();
+ }
+
+ public void ShouldAdd()
+ {
+ log.WhereAmI();
+ calculator.Add(2, 3).ShouldEqual(5);
+ }
+
+ [Skip]
+ public void ShouldNotBeCalled()
+ {
+ throw new Exception("This test should be skipped.");
+ }
+
+ public void ShouldSubtract()
+ {
+ log.WhereAmI();
+ calculator.Subtract(5, 3).ShouldEqual(2);
+ }
+
+ public void Dispose()
+ {
+ log.WhereAmI();
+ log.ShouldHaveLines(
+ ".ctor",
+ "ShouldAdd",
+ "ShouldSubtract",
+ "Dispose");
+ }
+ }
+}
@@ -16,6 +16,15 @@ public void AssemblyStarted(Assembly assembly)
{
}
+ public void CaseSkipped(Case @case)
+ {
+ tdnet.TestFinished(new TestResult
+ {
+ Name = @case.Name,
+ State = TestState.Ignored
+ });
+ }
+
public void CasePassed(PassResult result)
{
var @case = result.Case;
@@ -161,12 +161,13 @@ public void ShouldExecuteAllCasesInAllDiscoveredTestClasses()
var listener = new StubListener();
var convention = new SelfTestConvention();
- convention.Execute(listener, typeof(SampleIrrelevantClass), typeof(PassTestClass), typeof(int), typeof(PassFailTestClass));
+ convention.Execute(listener, typeof(SampleIrrelevantClass), typeof(PassTestClass), typeof(int), typeof(PassFailTestClass), typeof(SkipTestClass));
listener.Entries.ShouldEqual("Fixie.Tests.Conventions.ConventionTests+PassTestClass.PassA passed.",
"Fixie.Tests.Conventions.ConventionTests+PassTestClass.PassB passed.",
"Fixie.Tests.Conventions.ConventionTests+PassFailTestClass.Fail failed: 'Fail' failed!",
- "Fixie.Tests.Conventions.ConventionTests+PassFailTestClass.Pass passed.");
+ "Fixie.Tests.Conventions.ConventionTests+PassFailTestClass.Pass passed.",
+ "Fixie.Tests.Conventions.ConventionTests+SkipTestClass.Skip skipped.");
}
public void ShouldAllowRandomShufflingOfCaseExecutionOrder()
@@ -178,12 +179,13 @@ public void ShouldAllowRandomShufflingOfCaseExecutionOrder()
.CreateInstancePerTestClass()
.ShuffleCases(new Random(1));
- convention.Execute(listener, typeof(SampleIrrelevantClass), typeof(PassTestClass), typeof(int), typeof(PassFailTestClass));
+ convention.Execute(listener, typeof(SampleIrrelevantClass), typeof(PassTestClass), typeof(int), typeof(PassFailTestClass), typeof(SkipTestClass));
listener.Entries.ShouldEqual("Fixie.Tests.Conventions.ConventionTests+PassTestClass.PassB passed.",
"Fixie.Tests.Conventions.ConventionTests+PassTestClass.PassA passed.",
"Fixie.Tests.Conventions.ConventionTests+PassFailTestClass.Fail failed: 'Fail' failed!",
- "Fixie.Tests.Conventions.ConventionTests+PassFailTestClass.Pass passed.");
+ "Fixie.Tests.Conventions.ConventionTests+PassFailTestClass.Pass passed.",
+ "Fixie.Tests.Conventions.ConventionTests+SkipTestClass.Skip skipped.");
}
class SampleIrrelevantClass
@@ -203,5 +205,10 @@ class PassFailTestClass
public void Pass() { }
public void Fail() { throw new FailureException(); }
}
+
+ class SkipTestClass
+ {
+ public void Skip() { throw new ShouldBeUnreachableException(); }
+ }
}
}
@@ -150,6 +150,74 @@ public void ShouldFailAllCasesWhenConstructingPerTestClassAndCustomFactoryThrows
"Factory");
}
+ public void ShouldSkipConstructingPerCaseWhenAllCasesSkipped()
+ {
+ Convention.ClassExecution
+ .CreateInstancePerCase();
+
+ Convention.CaseExecution
+ .Skip(x => true);
+
+ var output = Run();
+
+ output.ShouldHaveResults(
+ "SampleTestClass.Pass skipped.",
+ "SampleTestClass.Fail skipped.");
+
+ output.ShouldHaveLifecycle();
+ }
+
+ public void ShouldSkipConstructingPerTestClassWhenAllCasesSkipped()
+ {
+ Convention.ClassExecution
+ .CreateInstancePerTestClass();
+
+ Convention.CaseExecution
+ .Skip(x => true);
+
+ var output = Run();
+
+ output.ShouldHaveResults(
+ "SampleTestClass.Pass skipped.",
+ "SampleTestClass.Fail skipped.");
+
+ output.ShouldHaveLifecycle();
+ }
+
+ public void ShouldSkipConstructingPerCaseUsingCustomFactoryWhenAllCasesSkipped()
+ {
+ Convention.ClassExecution
+ .CreateInstancePerCase(Factory);
+
+ Convention.CaseExecution
+ .Skip(x => true);
+
+ var output = Run();
+
+ output.ShouldHaveResults(
+ "SampleTestClass.Pass skipped.",
+ "SampleTestClass.Fail skipped.");
+
+ output.ShouldHaveLifecycle();
+ }
+
+ public void ShouldSkipConstructingPerTestClassUsingCustomFactoryWhenAllCasesSkipped()
+ {
+ Convention.ClassExecution
+ .CreateInstancePerTestClass(Factory);
+
+ Convention.CaseExecution
+ .Skip(x => true);
+
+ var output = Run();
+
+ output.ShouldHaveResults(
+ "SampleTestClass.Pass skipped.",
+ "SampleTestClass.Fail skipped.");
+
+ output.ShouldHaveLifecycle();
+ }
+
static object Factory(Type testClass)
{
WhereAmI();
@@ -22,6 +22,7 @@ public void ShouldReportResultsToTheConsole()
console.Lines()
.Select(x => Regex.Replace(x, @":line \d+", ":line #")) //Avoid brittle assertion introduced by stack trace line numbers.
.ShouldEqual(
+ "Test '" + testClass + ".SkipA' skipped",
"Console.Out: FailA",
"Console.Error: FailA",
"Console.Out: FailB",
@@ -70,6 +71,8 @@ public void FailB()
public void PassC() { WhereAmI(); }
+ public void SkipA() { throw new ShouldBeUnreachableException(); }
+
static void WhereAmI([CallerMemberName] string member = null)
{
Console.Out.WriteLine("Console.Out: " + member);
@@ -23,6 +23,8 @@ public void ShouldReportResultsToTheConsoleInTeamCityFormat()
.Select(x => Regex.Replace(x, @":line \d+", ":line #")) //Avoid brittle assertion introduced by stack trace line numbers.
.Select(x => Regex.Replace(x, @"duration='\d+'", "duration='#'")) //Avoid brittle assertion introduced by durations.
.ShouldEqual(
+ "##teamcity[testIgnored name='" + testClass + ".SkipA']",
+
"Console.Out: FailA",
"Console.Error: FailA",
"Console.Out: FailB",
@@ -83,6 +85,8 @@ public void FailB()
public void PassC() { WhereAmI(); }
+ public void SkipA() { throw new ShouldBeUnreachableException(); }
+
static void WhereAmI([CallerMemberName] string member = null)
{
Console.Out.WriteLine("Console.Out: " + member);
@@ -14,6 +14,11 @@ public void AssemblyStarted(Assembly assembly)
{
}
+ public void CaseSkipped(Case @case)
+ {
+ log.Add(string.Format("{0} skipped.", @case.Name));
+ }
+
public void CasePassed(PassResult result)
{
var @case = result.Case;
@@ -7,20 +7,24 @@ public class AssemblyResult
{
readonly int passed;
readonly int failed;
+ readonly int skipped;
- public AssemblyResult(int passed, int failed)
+ public AssemblyResult(int passed, int skipped, int failed)
{
this.passed = passed;
this.failed = failed;
+ this.skipped = skipped;
}
public int Passed { get { return passed; } }
+ public int Skipped { get { return skipped; } }
+
public int Failed { get { return failed; } }
public int Total
{
- get { return Passed + Failed; }
+ get { return Passed + Skipped + Failed; }
}
}
}
@@ -11,10 +11,13 @@ public class CaseBehaviorBuilder
public CaseBehaviorBuilder()
{
Behavior = new Invoke();
+ SkipPredicate = @case => false;
}
public CaseBehavior Behavior { get; private set; }
+ public Func<Case, bool> SkipPredicate { get; private set; }
+
public CaseBehaviorBuilder Wrap(CaseBehaviorAction outer)
{
Behavior = new WrapBehavior(outer, Behavior);
@@ -40,6 +43,12 @@ public CaseBehaviorBuilder SetUpTearDown(CaseAction setUp, CaseAction tearDown)
});
}
+ public CaseBehaviorBuilder Skip(Func<Case, bool> skipPredicate)
+ {
+ SkipPredicate = skipPredicate;
+ return this;
+ }
+
class WrapBehavior : CaseBehavior
{
readonly CaseBehaviorAction outer;
@@ -38,8 +38,17 @@ public void Execute(Listener listener, params Type[] candidateTypes)
var methods = Methods.Filter(testClass);
var cases = methods.SelectMany(method => CasesForMethod(testClass, method)).ToArray();
+ var casesBySkipState = cases.ToLookup(CaseExecution.SkipPredicate);
+ var casesToSkip = casesBySkipState[true];
+ var casesToExecute = casesBySkipState[false];
+ foreach (var @case in casesToSkip)
+ {
+ listener.CaseSkipped(@case);
+ }
- var caseExecutions = cases.Select(@case => new CaseExecution(@case)).ToArray();
+ var caseExecutions = casesToExecute.Select(@case => new CaseExecution(@case)).ToArray();
+ if (!caseExecutions.Any())
+ continue;
ClassExecution.Behavior.Execute(testClass, this, caseExecutions);
@@ -15,6 +15,9 @@ public SelfTestConvention()
ClassExecution
.SortCases((x, y) => String.Compare(x.Name, y.Name, StringComparison.Ordinal));
+
+ CaseExecution
+ .Skip(@case => @case.Method.Name.StartsWith("Skip"));
}
}
}
View
@@ -22,6 +22,11 @@ public static Foreground Red
get { return new Foreground(ConsoleColor.Red); }
}
+ public static Foreground Yellow
+ {
+ get { return new Foreground(ConsoleColor.Yellow); }
+ }
+
public static Foreground DarkGray
{
get { return new Foreground(ConsoleColor.DarkGray); }
View
@@ -5,6 +5,7 @@ namespace Fixie
public interface Listener
{
void AssemblyStarted(Assembly assembly);
+ void CaseSkipped(Case @case);
void CasePassed(PassResult result);
void CaseFailed(FailResult result);
void AssemblyCompleted(Assembly assembly, AssemblyResult result);
Oops, something went wrong.

0 comments on commit c46730f

Please sign in to comment.