Skip to content

Commit 83ac1b3

Browse files
author
Jake Ginnivan
committed
Added docs site
1 parent 0abd3b1 commit 83ac1b3

File tree

9 files changed

+171
-20
lines changed

9 files changed

+171
-20
lines changed

ConventionTests.sln

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
77
ProjectSection(SolutionItems) = preProject
88
appveyor.yml = appveyor.yml
99
GitVersionConfig.yaml = GitVersionConfig.yaml
10+
mkdocs.yml = mkdocs.yml
1011
README.md = README.md
1112
EndProjectSection
1213
EndProject
@@ -29,6 +30,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleApp", "Samples\Sample
2930
EndProject
3031
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleApp.Tests", "Samples\SampleApp.Tests\SampleApp.Tests.csproj", "{8FEF48A8-6FF5-4B65-B84A-6690D735C703}"
3132
EndProject
33+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{D822A12B-D358-48BC-8158-EB5CC253C858}"
34+
ProjectSection(SolutionItems) = preProject
35+
Docs\defining-conventions.md = Docs\defining-conventions.md
36+
Docs\index.md = Docs\index.md
37+
mkdocs.yml = mkdocs.yml
38+
Docs\symmetric-conventions.md = Docs\symmetric-conventions.md
39+
EndProjectSection
40+
EndProject
3241
Global
3342
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3443
Debug|Any CPU = Debug|Any CPU

Docs/defining-conventions.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
layout: layout
3+
title: Defining Conventions
4+
---
5+
6+
If you want to define your own conventions, it is really easy.
7+
8+
### Step 1
9+
Create a new class, inheriting from `IConvention<TData>`, lets use the **must have default constructor** convention as an example
10+
11+
public class AllClassesHaveDefaultConstructor : IConvention<Types>
12+
{
13+
public void Execute(Types data, IConventionResult result)
14+
{
15+
16+
}
17+
}
18+
19+
### Step 2
20+
Write the convention logic
21+
22+
var typesWithoutDefaultCtor = data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false);
23+
result.Is("Types must have a default constructor", typesWithoutDefaultCtor);
24+
25+
### Final result
26+
27+
public class AllClassesHaveDefaultConstructor : IConvention<Types>
28+
{
29+
public void Execute(Types data, IConventionResult result)
30+
{
31+
var typesWithoutDefaultCtor = data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false);
32+
result.Is("Types must have a default constructor", typesWithoutDefaultCtor);
33+
}
34+
}
35+
36+
## IConventionResult
37+
Currently convention tests supports two types of convention results, the one we have just seen is a normal result. The other type is a symmetric result, which is the result for a symmetric convention.
38+
39+
An example of a symmetric convention is `ClassTypeHasSpecificNamespace`. It can verify a particular class type (dto, domain object, event handler) lives in a certain namespace, but it will also verify that ONLY that class type lives in that namespace. `new ClassTypeHasSpecificNamespace(t => t.Name.EndsWith("Dto"), "TestAssembly.Dtos", "Dto")`
40+
41+
The result will look like this:
42+
43+
result.IsSymmetric(
44+
string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck),
45+
string.Format("Non-{0}s must not be under the '{1}' namespace", classType, namespaceToCheck),
46+
classIsApplicable,
47+
TypeLivesInSpecifiedNamespace,
48+
data.TypesToVerify);
49+
50+
See [Symmetric Conventions](SymmetricConventions.html) for more information.

Docs/imgs/SymmetricConventions.png

126 KB
Loading

Docs/index.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
3+
layout: layout
4+
5+
title: ConventionTests
6+
---
7+
8+
## What is ConventionTests?
9+
10+
Convention over Configuration is a great way to cut down repetitive boilerplate code. But how do you validate that your code adheres to your conventions?
11+
12+
ConventionTests provides a simple API to build validation rules for creating convention validation tests.
13+
14+
## Getting Started
15+
It is really easy to get started with ConventionTests, there are a number of included conventions that come out of the box:
16+
17+
- All Classes Have Default Constructor
18+
- All Methods are Virtual
19+
- Class type has specific namespace (for example, all dtos must live in the ProjectName.Dtos namespace)
20+
- Files are Embedded Resources
21+
- Project does not reference dlls from Bin or Obj directory
22+
- Others are being added over time and you can create your own custom ones
23+
24+
### Writing your first Convention test
25+
26+
#### 1. Using your favourite testing framework, create a new test. Lets call it:
27+
28+
`entities_must_have_default_constructor`
29+
30+
#### 2. Define some types to validate against a convention
31+
32+
The following line get a list of all the types in the assembly that contains `SampleDomainClass`.
33+
34+
var itemsToVerify = Types.InAssemblyOf<SampleDomainClass>();
35+
36+
There are also overloads to restrict the types to a specific namespace within the assembly.
37+
38+
#### 3. Assert the convention
39+
40+
Now we have a list of types to check, we can use one of the pre-built conventions and check all of the types against this convention:
41+
42+
`Convention.Is(new AllClassesHaveDefaultConstructor(), itemsToVerify);`
43+
44+
#### That's it!
45+
46+
When you run this convention, if any of the types don't meet with the chosen convention, it fails and an exception will be thrown, which will look something like this:
47+
48+
ConventionFailedException
49+
Message = Failed: 'Types must have a default constructor'
50+
-----------------------------------------------------------------
51+
52+
TestAssembly.ClassWithNoDefaultCtor
53+
TestAssembly.ClassWithPrivateDefaultCtor
54+
55+
How cool is that!
56+
57+
### Reporting
58+
If you would like to use ConventionTests reporting features, you just have to opt in by specifying the reporter you want. This makes it easy to add your own reporters, for example a WikiReporter may be better than the `HtmlReporter`
59+
60+
In your `Properties\AssemblyInfo.cs` file add the reporters you want. This are global reporters which will report the results of all conventions.
61+
62+
[assembly: ConventionReporter(typeof(HtmlConventionResultsReporter))]
63+
[assembly: ConventionReporter(typeof(MarkdownConventionResultsReporter))]
64+
65+
Then if you look in the directory where your test assembly is, there will be an html report called `Conventions.htm`, serving as living documentation!

Docs/symmetric-conventions.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
layout: layout
3+
title: Symmetric Conventions
4+
---
5+
6+
Symmetric conventions will verify a convention and also the inverse of that convention.
7+
8+
An example of a symmetric convention is `ClassTypeHasSpecificNamespace`. It can verify a particular class type (dto, domain object, event handler) lives in a certain namespace, but it will also verify that ONLY that class type lives in that namespace.
9+
10+
Take a look at the following Venn Diagram
11+
12+
![SymmetricConventions](./imgs/SymmetricConventions.png)
13+
14+
In the above example, let us say 'Dtos must live under Project.Dtos'. This means that all data contains ALL TYPES in the assembly, correct data is a dto living in the Project.Dtos namespace. But we have two failure conditions.
15+
16+
The first is if a Dto is outside the Project.Dtos namespace, the convention fails. The second is if a non-dto class lives inside the Project.Dtos namespace.
17+
18+
### How to use a symmetric convention
19+
20+
var types = new Types("Types in MyProject")
21+
{
22+
TypesToVerify = typeof(MyDto).Assembly.GetTypes()
23+
};
24+
var convention = new ClassTypeHasSpecificNamespace(
25+
classIsApplicable: t => t.Name.EndsWith("Dto"),
26+
namespaceToCheck : "MyProject.Dtos",
27+
classType: "Dto");
28+
Convention.Is(convention, types);
29+
30+
As you can see, symmetric conventions are no different to enforce
31+
32+
### Writing a symmetric convention
33+
See [Defining Conventions](DefiningConventions.html)

TestStack.ConventionTests.Autofac/AutofacRegistrations.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,11 @@ public AutofacRegistrations(IComponentRegistry componentRegistry)
1919
this.componentRegistry = componentRegistry;
2020
}
2121

22-
public string Description
23-
{
24-
get { return "All AutofacContainer Registrations"; }
25-
}
22+
public string Description => "All AutofacContainer Registrations";
2623

27-
public bool HasData
28-
{
29-
get { return true; }
30-
}
24+
public bool HasData => true;
3125

32-
public IComponentRegistry ComponentRegistry
33-
{
34-
get { return componentRegistry; }
35-
}
26+
public IComponentRegistry ComponentRegistry => componentRegistry;
3627

3728
public Type GetConcreteType(IComponentRegistration r)
3829
{

TestStack.ConventionTests.Autofac/CanResolveAllRegisteredServices.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,8 @@ public void Execute(AutofacRegistrations data, IConventionResultContext result)
3737
result.Is("Can resolve all types registered with Autofac", failingTypes);
3838
}
3939

40-
public string ConventionReason
41-
{
42-
get
43-
{
44-
return "Container resolution failings are runtime exceptions, this convention allows you to detect missing registrations faster!";
45-
}
46-
}
40+
public string ConventionReason =>
41+
"Container resolution failings are runtime exceptions, this convention allows you to detect missing registrations faster!";
4742

4843
private IEnumerable<Type> GetGenericFactoryTypes(AutofacRegistrations data, IComponentRegistration componentRegistration)
4944
{

TestStack.ConventionTests/Convention.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static void Execute<TDataSource>(IConvention<TDataSource> convention, TDataSourc
5959
IEnumerable<IResultsProcessor> processors, ITestResultProcessor resultProcessor)
6060
where TDataSource : IConventionData
6161
{
62-
var dataDescription = string.Format("{0} in {1}", data.GetType().GetSentenceCaseName(), data.Description);
62+
var dataDescription = $"{data.GetType().GetSentenceCaseName()} in {data.Description}";
6363
var context = new ConventionContext(dataDescription, Formatters, processors, resultProcessor);
6464
context.Execute(convention, data);
6565
}

mkdocs.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
site_name: ConventionTests
2+
theme: readthedocs
3+
repo_url: https://github.com/TestStack/TestStack.ConventionTests
4+
5+
pages:
6+
- Home: index.md
7+
- 'Defining Conventions': 'defining-conventions.md'
8+
- 'Symmetric Conventions': 'symmetric-conventions.md'

0 commit comments

Comments
 (0)