Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<ProjectGuid>{69395747-4A18-4A09-92F9-EED4032F7677}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnitTestProject1</RootNamespace>
<AssemblyName>UnitTestProject1</AssemblyName>
<RootNamespace>NSpec.Runner.Tests</RootNamespace>
<AssemblyName>NSpec.Runner.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
Expand Down Expand Up @@ -59,8 +59,8 @@
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="DebuggerShim.cs" />
<Compile Include="UnitTest1.cs" />
<Compile Include="TestSpecification.cs" />
<Compile Include="NSpecRunnerTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
Expand All @@ -70,7 +70,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
Expand Down
87 changes: 87 additions & 0 deletions NSpec.Runner.Tests/NSpecRunnerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NSpec;
using NSpec.Runner;

namespace NSpec.Runner.Tests
{
[TestClass]
public class NSpecRunnerTest : nspec
{

[TestMethod, TestSpecification]
public void When_Writing_A_Test_Spec()
{
bool theTruth = false;

context["and when dealing with other people,"] = () =>
{
before = () => theTruth = true;
it["it will be honest."] = () => theTruth.should_be(true);
it["it will open doors for old ladies."] = () => theTruth.should_be(true);

context["and when dealing with old dudes that are grumpy,"] = () =>
{
before = () => theTruth = false;

it["it will tell a knock knock joke."] = () => theTruth.should_be(false);
};

context["and when dealing with old dudes that are not grumpy,"] = () =>
{
it["it will give them a high five."] = () => theTruth.should_be(true);
};
};
}

[TestMethod, TestSpecification]
public void When_Writing_A_Test_Spec_With_Failues()
{
bool theTruth = false;

context["and when dealing with other people,"] = () =>
{
before = () => theTruth = false;
it["it will be honest."] = () => theTruth.should_be(true);
it["it will open doors for old ladies."] = () => theTruth.should_be(true);

context["and when dealing with old dudes that are grumpy,"] = () =>
{
before = () => theTruth = true;

it["it will tell a knock knock joke."] = () => theTruth.should_be(false);
};

context["and when dealing with old dudes that are not grumpy,"] = () =>
{
it["it will give them a high five."] = () => theTruth.should_be(true);
};
};
}

[TestMethod, TestSpecification]
public void When_Writing_A_Test_Spec_With_Pendings()
{
context["and you haven't finished the specs"] = () =>
{
it["you should declare them as TODO"] = todo;
it["and the test result should be inconclusiv"] = () => { };
it["and the output should contain Pending = 1"] = () => { };
};
}

[TestMethod, TestSpecification, Ignore]
public void When_Writing_A_Test_Spec_With_Ingnore_Attribute()
{
it["it should be ignored"] = () => { Assert.Fail("it should be ignored"); };
}

[TestMethod, TestSpecification(FailFast=true)]
public void When_Writing_A_Test_Spec_With_FailFast()
{
it["it should fail on first assertation"] = () => { 1.is_greater_than(2); };
it["and not here"] = () => { 2.is_less_than(1); Assert.Fail("this should not be called"); };
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnitTestProject1")]
[assembly: AssemblyTitle("NSpec.Runner.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UnitTestProject1")]
[assembly: AssemblyProduct("NSpec.Runner.Tests")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
Expand Down
49 changes: 49 additions & 0 deletions NSpec.Runner.Tests/TestSpecification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace NSpec.Runner.Tests
{
[Serializable, TestClass]
public class TestSpecification : global::NSpec.Runner.TestSpecification
{
public static TestContext TestContext { get; protected set; }

[AssemblyInitialize]
public static void AssemblyInit(TestContext context)
{
// by marking this class as TestClass and adding an AssemblyInitialize attribut
// we can reliably determine if run via Test Explorer (or hopefully any other MsTest compatible runner)
//
// if TestContext != null Enabled will be false
// and test will be processed by console runner
TestContext = context;
}

public override void ProcessResults(NSpecResults results)
{
if (results.HasFailures)
Assert.Fail(results.Message);
else if (results.HasPendings)
Assert.Inconclusive(results.Message);
}

public override bool ShouldIgnore(MethodBase method)
{
return method.GetCustomAttribute<IgnoreAttribute>() != null;
}

public override bool Enabled
{
get
{
return TestContext != null;
}
}

}
}
File renamed without changes.
9 changes: 6 additions & 3 deletions NSpec.Runner.sln
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30723.0
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSpec.Runner", "NSpec.Runner\NSpec.Runner.csproj", "{4FD94255-9A5E-4B63-8F82-337F4FF0FC24}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestProject1", "UnitTestProject1\UnitTestProject1.csproj", "{69395747-4A18-4A09-92F9-EED4032F7677}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSpec.Runner.Tests", "NSpec.Runner.Tests\NSpec.Runner.Tests.csproj", "{69395747-4A18-4A09-92F9-EED4032F7677}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -25,4 +25,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(CodealikeProperties) = postSolution
SolutionGuid = 651d86ea-12f9-4d34-920b-903e59654049
EndGlobalSection
EndGlobal
6 changes: 6 additions & 0 deletions NSpec.Runner/NSpec.Runner.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
<ItemGroup>
<Compile Include="DebuggerShim.cs" />
<Compile Include="MethodContextRunner.cs" />
<Compile Include="NSpecResult.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SingleClassGetter.cs" />
<Compile Include="MethodContextBuilder.cs" />
Expand All @@ -60,6 +61,11 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\packages\nspec.1.0.5\tools\nunit.framework.dll">
<Link>nunit.framework.dll</Link>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\PostSharp.4.0.38\tools\PostSharp.targets" Condition="Exists('..\packages\PostSharp.4.0.38\tools\PostSharp.targets')" />
<Target Name="EnsurePostSharpImported" BeforeTargets="BeforeBuild" Condition="'$(PostSharp30Imported)' == ''">
Expand Down
37 changes: 37 additions & 0 deletions NSpec.Runner/NSpecResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using NSpec.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NSpec.Runner
{
[Serializable]
public class NSpecResults
{
private readonly string message;
private readonly ContextCollection results;

internal NSpecResults(ContextCollection results)
{
this.results = results;
this.message = String.Format("{0} Examples, {1} Failed, {2} Pending",
results.Examples().Count(),
results.Failures().Count(),
results.Pendings().Count()
);
}


public bool HasFailures { get { return results.Failures().Any(); } }

public bool HasPendings { get { return results.Pendings().Any(); } }

public bool HasExamples { get { return results.Examples().Any(); } }

public string Message { get { return message; } }

}

}
2 changes: 2 additions & 0 deletions NSpec.Runner/TestFailedException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ namespace NSpec.Runner
{
public class TestFailedException : Exception
{
public TestFailedException(string message) : base(message) { }
public TestFailedException(string message, Exception innerException) : base(message, innerException) { }
}
}
78 changes: 72 additions & 6 deletions NSpec.Runner/TestSpecification.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;
Expand All @@ -19,11 +20,38 @@ public class TestSpecification : MethodInterceptionAspect
[XmlArrayItem(Type = typeof(MethodBase))]
[XmlArray]
private static List<MethodBase> methodsThatHaveBeenPrepared = new List<MethodBase>();

static TestSpecification()
{
// NSpec.AssertionExtensions methods are wrappers for nunit assertations but NSpec has no direct dependency on nunit.framework itself.
// That's why we include nunit.framework.dll from packages\nspec.1.0.5\tools as an embedded resource
// and use AssemblyResolve event to dynamically load it at runtime
// otherwise specs would wile with a FileNotFoundException
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}

private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// https://blogs.msdn.microsoft.com/microsoft_press/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition/
var assemblyName = new AssemblyName(args.Name);
String resourceName = "NSpec.Runner." + assemblyName.Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
if (stream == null) return null;
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}

public override void OnInvoke(MethodInterceptionArgs args)
{

// skip ignored specs
if (ShouldIgnore(args.Method)) return;

// if the method has been prepared, we need to actually execute the function
if (methodsThatHaveBeenPrepared.Contains(args.Method))
if (methodsThatHaveBeenPrepared.Contains(args.Method) || !Enabled)
{
base.OnInvoke(args);
return;
Expand All @@ -35,7 +63,8 @@ public override void OnInvoke(MethodInterceptionArgs args)
// prepare the npsec content of the function
var finder = new SingleClassGetter(args.Instance.GetType());
var builder = new MethodContextBuilder(finder, new DefaultConventions());
var runner = new MethodContextRunner(builder, new ConsoleFormatter(), false);
var formatter = new ConsoleFormatter(); // { WriteLineDelegate = value => Console.WriteLine(Regex.Replace(value, @"\r(?!\n)", Environment.NewLine)) }; // custom formatter to replace \r with newline
var runner = new MethodContextRunner(builder, formatter, this.FailFast);

// set up the contexts for the method
var methodInfo = args.Method as MethodInfo;
Expand All @@ -45,13 +74,50 @@ public override void OnInvoke(MethodInterceptionArgs args)
var builtContexts = contexts.Build();
var results = runner.Run(builtContexts);

// wrap result and handle
var nspecResults = new NSpecResults(results);
ProcessResults(nspecResults);

}

/// <summary>
/// Override to add Test Framework specific result handling.
/// </summary>
/// <param name="results"></param>
public virtual void ProcessResults(NSpecResults results)
{
// if there were any failures, raise the exception so that the test framework has an error
if (results.Failures().Any())
{
throw new TestFailedException();
}
if (results.HasFailures)
throw new TestFailedException(results.Message);

// tests all passed
}

/// <summary>
/// Determine if a certain test should be ignored
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
public virtual bool ShouldIgnore(MethodBase method)
{
return false;
}

/// <summary>
/// If false specs are not intercepted. Defaults to true, unless running from NSpecRunner.exe
/// </summary>
public virtual bool Enabled
{
get
{
return !Process.GetCurrentProcess().ProcessName.Equals("NSpecRunner", StringComparison.OrdinalIgnoreCase);
}
}

/// <summary>
/// Configue if test should fail fast or not. Only applies if run if Enabled
/// </summary>
public virtual bool FailFast { get; set; }

}
}
Loading