-
Notifications
You must be signed in to change notification settings - Fork 19
another iteration of API experiments #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,50 @@ | ||
namespace TestStack.ConventionTests.Tests | ||
{ | ||
using System.Xml.Linq; | ||
using ApprovalTests; | ||
using ApprovalTests.Reporters; | ||
using NSubstitute; | ||
using NUnit.Framework; | ||
using TestStack.ConventionTests.Conventions; | ||
using TestStack.ConventionTests.Helpers; | ||
using TestStack.ConventionTests.Internal; | ||
using TestStack.ConventionTests.Tests.Properties; | ||
|
||
[TestFixture] | ||
[UseReporter(typeof(DiffReporter))] | ||
[UseReporter(typeof (DiffReporter))] | ||
public class ProjectBasedConventions | ||
{ | ||
public ProjectBasedConventions() | ||
{ | ||
Convention.Settings.AssertInclunclusive = Assert.Inconclusive; | ||
Convention.Settings.AssertZero = (v, m) => Assert.AreEqual(0, v, m); | ||
} | ||
|
||
[Test] | ||
public void ReferencingBinObj() | ||
{ | ||
// Actual syntax will be (when not testing): | ||
// | ||
// Convention.Is<ProjectDoesNotReferenceDllsFromBinOrObjDirectories>(new[] { typeof(ProjectBasedConventions).Assembly }); | ||
// | ||
|
||
var projectProvider = Substitute.For<IProjectProvider>(); | ||
var projectLocator = Substitute.For<IProjectLocator>(); | ||
projectProvider | ||
.LoadProjectDocument(Arg.Any<string>()) | ||
.Returns(XDocument.Parse(Resources.ProjectFileWithBinReference)); | ||
|
||
var convention = new ProjectDoesNotReferenceDllsFromBinOrObjDirectories(projectLocator, projectProvider); | ||
|
||
var exception = Assert.Throws<ConventionFailedException>(() => | ||
Convention.Is(convention, new[] { typeof(ProjectBasedConventions).Assembly })); | ||
Approvals.Verify(exception.Message); | ||
Convention.Is(new ProjectDoesNotReferenceDllsFromBinOrObjDirectories(), | ||
new Project(typeof (ProjectBasedConventions).Assembly, projectProvider, projectLocator)); | ||
} | ||
|
||
[Test] | ||
public void ScriptsNotEmbeddedResources() | ||
{ | ||
// Actual syntax will be (when not testing): | ||
// | ||
// Convention.Is<FilesAreEmbeddedResources>(new[] { typeof(ProjectBasedConventions).Assembly }, i => i.EndsWith(".sql")); | ||
// | ||
|
||
var projectProvider = Substitute.For<IProjectProvider>(); | ||
var projectLocator = Substitute.For<IProjectLocator>(); | ||
projectProvider | ||
.LoadProjectDocument(Arg.Any<string>()) | ||
.Returns(XDocument.Parse(Resources.ProjectFileWithInvalidSqlScriptFile)); | ||
|
||
var convention = new FilesAreEmbeddedResources(projectLocator, projectProvider); | ||
|
||
var exception = Assert.Throws<ConventionFailedException>(() => | ||
Convention.Is(convention, new[] { typeof(ProjectBasedConventions).Assembly }, i => i.EndsWith(".sql"))); | ||
Approvals.Verify(exception.Message); | ||
Convention.Is(new FilesAreEmbeddedResources(), | ||
new Project(typeof (ProjectBasedConventions).Assembly, projectProvider, projectLocator) | ||
{ | ||
Includes = i => i.EndsWith(".sql") | ||
}); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,40 @@ | ||
namespace TestStack.ConventionTests.Tests | ||
{ | ||
using System; | ||
using ApprovalTests; | ||
using ApprovalTests.Reporters; | ||
using NUnit.Framework; | ||
using TestAssembly; | ||
using TestStack.ConventionTests.Conventions; | ||
|
||
[TestFixture] | ||
[UseReporter(typeof(DiffReporter))] | ||
[UseReporter(typeof (DiffReporter))] | ||
public class TypeBasedConventions | ||
{ | ||
readonly Type[] itemsToVerify; | ||
readonly Types nhibernateEntities; | ||
|
||
public TypeBasedConventions() | ||
{ | ||
itemsToVerify = typeof(SampleDomainClass).Assembly.GetTypes(); | ||
// TODO: This should go to some sort of autodiscovery mechanism so users don't have to see this shit | ||
Convention.Settings.AssertInclunclusive = Assert.Inconclusive; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need this. I think it is fine to have our own ConventionFailedException. The test will still fail, and I think it is actually more informative than, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My concern was around how different test runners would handle non-standard exceptions. Would the test failure report be as neat as if it was an expected I saw your screenshots from the resharper runner, but do all popular runners handle that? Does MsTest and XUnit behave similarly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nCrunch looked good, and I know xUnit is fine with it. They are setup for showing any sort of exception, because often tests fail because of a null reference exception, or some other sort of exception. Any sort of exception has to be readable. I don't beleive any runner does anything special with their assert exception types, they are just custom exceptions which the framework throws. Also frameworks like shouldly would throw their own custom exceptions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds good Krzysztof Kozmic On Wednesday, 31 July 2013 at 10:59 PM, Jake Ginnivan wrote:
|
||
Convention.Settings.AssertZero = (v, m) => Assert.AreEqual(0, v, m); | ||
|
||
var itemsToVerify = typeof (SampleDomainClass).Assembly.GetTypes(); | ||
nhibernateEntities = new Types | ||
{ | ||
ApplicableTypes = itemsToVerify, | ||
HasApprovedExceptions = false | ||
}; | ||
} | ||
|
||
[Test] | ||
public void all_methods_are_virtual() | ||
public void all_classes_have_default_constructor() | ||
{ | ||
var exception = Assert.Throws<ConventionFailedException>(() => Convention.Is<AllMethodsAreVirtual>(itemsToVerify)); | ||
|
||
Approvals.Verify(exception.Message); | ||
Convention.Is(new AllClassesHaveDefaultConstructor(), nhibernateEntities); | ||
} | ||
|
||
[Test] | ||
public void all_classes_have_default_constructor() | ||
public void all_methods_are_virtual() | ||
{ | ||
var exception = Assert.Throws<ConventionFailedException>(() => Convention.Is<AllClassesHaveDefaultConstructor>(itemsToVerify)); | ||
|
||
Approvals.Verify(exception.Message); | ||
Convention.Is(new AllMethodsAreVirtual(), nhibernateEntities); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,98 +1,45 @@ | ||
namespace TestStack.ConventionTests | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text; | ||
using ApprovalTests; | ||
|
||
public static class Convention | ||
{ | ||
public static void Is<T, T2>(IEnumerable<T2> itemsToVerify) where T : ConventionData<T2>, new() | ||
{ | ||
Is(new T(), itemsToVerify); | ||
} | ||
public static void Is<T, T2>(IEnumerable<T2> itemsToVerify, Func<string, bool> filter) | ||
where T : ConventionData<T2>, IRuntimeFilter<string>, new() | ||
{ | ||
Is(new T(), itemsToVerify); | ||
} | ||
public static void Is<T, T2, TItem>(IEnumerable<T2> itemsToVerify, Func<TItem, bool> filter) | ||
where T : ConventionData<T2>, IRuntimeFilter<TItem>, new() | ||
{ | ||
Is(new T(), itemsToVerify); | ||
} | ||
|
||
//Item.Is<ConventionData<Type>> | ||
public static void Is<T>(IEnumerable<Type> itemsToVerify) where T : ConventionData<Type>, new() | ||
{ | ||
Is(new T(), itemsToVerify); | ||
} | ||
public static void Is<T>(IEnumerable<Type> itemsToVerify, Func<string, bool> filter) where T : ConventionData<Type>, IRuntimeFilter<string>, new() | ||
{ | ||
Is(new T(), itemsToVerify, filter); | ||
} | ||
public static void Is<T, TItem>(IEnumerable<Type> itemsToVerify, Func<TItem, bool> filter) where T : ConventionData<Type>, IRuntimeFilter<TItem>, new() | ||
{ | ||
Is(new T(), itemsToVerify, filter); | ||
} | ||
public static readonly ConventionSettings Settings = new ConventionSettings(); | ||
|
||
//Item.Is<ConventionData<Assembly>> | ||
public static void Is<T>(IEnumerable<Assembly> itemsToVerify) where T : ConventionData<Assembly>, new() | ||
public static void Is<TData>(IConvention<TData> convention, TData data) where TData : IConventionData | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WAY better |
||
{ | ||
Is(new T(), itemsToVerify); | ||
} | ||
public static void Is<T>(IEnumerable<Assembly> itemsToVerify, Func<string, bool> filter) where T : ConventionData<Assembly>, IRuntimeFilter<string>, new() | ||
{ | ||
Is(new T(), itemsToVerify, filter); | ||
} | ||
public static void Is<T, TItem>(IEnumerable<Assembly> itemsToVerify, Func<TItem, bool> filter) where T : ConventionData<Assembly>, IRuntimeFilter<TItem>, new() | ||
{ | ||
Is(new T(), itemsToVerify, filter); | ||
} | ||
|
||
public static void Is<T>(ConventionData<T> convention, IEnumerable<T> itemsToVerify) | ||
{ | ||
var results = Result(convention, itemsToVerify); | ||
if (!string.IsNullOrEmpty(results)) | ||
throw new ConventionFailedException(results); | ||
} | ||
|
||
public static void Is<TConvention, T>(TConvention convention, IEnumerable<T> itemsToVerify, Func<string, bool> itemFilter) | ||
where TConvention : ConventionData<T>, IRuntimeFilter<string> | ||
{ | ||
Is<TConvention, T, string>(convention, itemsToVerify, itemFilter); | ||
if (data.HasValidSource == false) | ||
{ | ||
// TODO: this would have to have a more reasonable and helpful message... | ||
Settings.AssertInclunclusive("No valid source in " + data); | ||
return; | ||
} | ||
var result = convention.Execute(data); | ||
if (result.IsConclusive == false) | ||
{ | ||
Settings.AssertInclunclusive(result.Message); | ||
return; | ||
} | ||
if (data.HasApprovedExceptions) | ||
{ | ||
// should we encapsulate Approvals behind Settings? | ||
Approvals.Verify(result.Message); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need to do this. I put in the .Result method which returns the string, which can then be approved or not in the test? I am also ok with putting an Exceptions property on This should be a choice the consumer of the framework makes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll do another PR with some tests to illustrate different scenarios I had in mind when building this (which is quite similar to how old ConventionTests worked). That should give us a clearer view of what solution would make most sense here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed my mind on this comment, and did the IsWithApprovedExceptions method, would love to see the other scenarios There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds good |
||
return; | ||
} | ||
Settings.AssertZero(result.InvalidResultsCount, result.Message); | ||
} | ||
|
||
public static void Is<TConvention, T, TItem>(TConvention convention, IEnumerable<T> itemsToVerify, Func<TItem, bool> itemFilter) | ||
where TConvention : ConventionData<T>, IRuntimeFilter<TItem> | ||
public class ConventionSettings | ||
{ | ||
var results = Result(convention, itemsToVerify, itemFilter); | ||
if (!string.IsNullOrEmpty(results)) | ||
throw new ConventionFailedException(results); | ||
} | ||
public Action<String> AssertInclunclusive; | ||
|
||
public static string Result<T>(ConventionData<T> convention, IEnumerable<T> itemsToVerify) | ||
{ | ||
var message = new StringBuilder(); | ||
var invalidItems = itemsToVerify.Where(i => !convention.Must(i)).ToArray(); | ||
if (!invalidItems.Any()) return null; | ||
public Action<int, string> AssertZero; | ||
|
||
message.AppendLine(convention.Description ?? "Convention has failing items"); | ||
foreach (var invalidType in invalidItems) | ||
public ConventionSettings() | ||
{ | ||
message.Append('\t'); | ||
convention.ItemDescription(invalidType, message); | ||
// TODO: initialize the type; | ||
} | ||
|
||
return message.ToString(); | ||
} | ||
|
||
public static string Result<TConvention, T, TItem>(TConvention convention, IEnumerable<T> itemsToVerify, Func<TItem, bool> itemFilter) | ||
where TConvention : ConventionData<T>, IRuntimeFilter<TItem> | ||
{ | ||
convention.SetFilter(itemFilter); | ||
return Result(convention, itemsToVerify); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,51 @@ | ||
namespace TestStack.ConventionTests | ||
{ | ||
using System; | ||
using System.Text; | ||
|
||
/// <summary> | ||
/// This is where we set what our convention is all about | ||
/// </summary> | ||
public class ConventionData : ConventionData<Type> | ||
public class ConventionData<TItem> | ||
{ | ||
public static readonly Predicate<TItem> None = _ => false; | ||
readonly Action<TItem, StringBuilder> defaultItemDescription = DefaultItemDescriptionMethod; | ||
|
||
public ConventionData() | ||
{ | ||
Must = None; | ||
OrderBy = HashCode; | ||
ItemDescription = defaultItemDescription; | ||
} | ||
|
||
public Func<TItem, object> OrderBy { get; set; } | ||
|
||
/// <summary> | ||
/// Descriptive text used for failure message in test. Should explan what is wrong, and how to fix it (how to make | ||
/// types that do not conform to the convention do so). | ||
/// </summary> | ||
public string Description { get; set; } | ||
|
||
/// <summary> | ||
/// This is the convention. The predicate should return <c>true</c> for types that do conform to the convention, and | ||
/// <c>false</c> otherwise | ||
/// </summary> | ||
public Predicate<TItem> Must { get; set; } | ||
|
||
public Action<TItem, StringBuilder> ItemDescription { get; set; } | ||
|
||
static void DefaultItemDescriptionMethod(TItem item, StringBuilder message) | ||
{ | ||
message.AppendLine(ReferenceEquals(item, null) ? "<<null>>" : item.ToString()); | ||
} | ||
|
||
object HashCode(TItem arg) | ||
{ | ||
if (ReferenceEquals(arg, null)) | ||
{ | ||
return 0; | ||
} | ||
return arg.GetHashCode(); | ||
} | ||
} | ||
} |
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is awesome...