├── src ├── build.bat ├── justeat-oss.snk ├── JustBehave.Tests │ ├── XunitConfig.cs │ ├── GlobalSuppression.cs │ ├── BehaviourTestBaseTests │ │ ├── FrameworkThrowingExceptions │ │ │ └── ExceptionIsThrown.cs │ │ ├── FrameworkRecordingExceptions │ │ │ └── ExceptionIsThrown.cs │ │ └── WhenExecuteIsInvokedByTestRunner.cs │ ├── Examples │ │ ├── WhenSomethingPasses.cs │ │ ├── WhenTestingForExceptions.cs │ │ ├── WhenTestingForExceptionsFromConstructors.cs │ │ ├── WhenAssertingAgainstLogs.cs │ │ └── WhenTestingSomethingWithDependencies.cs │ ├── JustBehave.Tests.ncrunchproject │ ├── AsyncBehaviourTests │ │ ├── WhenTestingForExceptions.cs │ │ ├── WhenAnXUnitTestPasses.cs │ │ └── WhenAnNUnitTestPasses.cs │ ├── JustBehave.Tests.csproj │ └── FakeTestCase.cs ├── JustBehave │ ├── ExceptionMode.cs │ ├── JustBehave.csproj │ ├── GlobalSuppression.cs │ ├── JustBehave.ncrunchproject │ ├── LogExt.cs │ ├── BehaviourTestBase.cs │ └── AsyncBehaviourTestBase.cs ├── create-package.bat ├── JustBehave.NUnit │ ├── ThenAttribute.cs │ ├── JustBehave.NUnit.csproj │ ├── AsyncBehaviourTest.cs │ └── BehaviourTest.cs ├── .editorconfig ├── JustBehave.xUnit │ ├── XBehaviourTest.cs │ ├── JustBehave.xUnit.csproj │ └── XAsyncBehaviourTest.cs ├── CustomDictionary.xml ├── JustBehave.sublime-project ├── JustBehave.ncrunchsolution ├── JustBehave.v2.ncrunchsolution ├── Directory.build.props ├── JustBehave.sln └── JustBehave.sln.DotSettings ├── test-screenshot.png ├── AUTHORS.txt ├── LICENSE.md ├── .gitattributes ├── .appveyor.yml ├── release.ps1 ├── CONTRIBUTING.md ├── README.md └── .gitignore /src/build.bat: -------------------------------------------------------------------------------- 1 | dotnet build -c Release JustBehave.sln 2 | -------------------------------------------------------------------------------- /src/justeat-oss.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justeat/JustBehave/HEAD/src/justeat-oss.snk -------------------------------------------------------------------------------- /test-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justeat/JustBehave/HEAD/test-screenshot.png -------------------------------------------------------------------------------- /src/JustBehave.Tests/XunitConfig.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | [assembly: CollectionBehavior(DisableTestParallelization = true)] 4 | -------------------------------------------------------------------------------- /src/JustBehave/ExceptionMode.cs: -------------------------------------------------------------------------------- 1 | namespace JustBehave 2 | { 3 | public enum ExceptionMode 4 | { 5 | Throw, 6 | Record 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/create-package.bat: -------------------------------------------------------------------------------- 1 | call build.bat 2 | if %errorlevel% neq 0 exit /b %errorlevel% 3 | 4 | dotnet pack -c Release JustBehave.sln 5 | if %errorlevel% neq 0 exit /b %errorlevel% 6 | -------------------------------------------------------------------------------- /src/JustBehave.NUnit/ThenAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace JustBehave 5 | { 6 | [AttributeUsage(AttributeTargets.Method)] 7 | public sealed class ThenAttribute : TestAttribute {} 8 | } 9 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | This file contains a list of people who have made significant contributions. 2 | 3 | Peter Mounce 4 | Payman Labbaf 5 | Anton Jefcoate -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | end_of_line = crlf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [**/*.{config,csproj,dotsettings,feature,fxcop,js,json,markdown,md,ncrunch*,ndepend,rb,targets,xml,xsd}] 12 | indent_size = 2 13 | 14 | [**/*.cs] 15 | indent_size = 4 16 | -------------------------------------------------------------------------------- /src/JustBehave.xUnit/XBehaviourTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace JustBehave 4 | { 5 | /// 6 | /// XUnit-based BehaviourTest. 7 | /// 8 | /// 9 | public abstract class XBehaviourTest : BehaviourTestBase 10 | { 11 | protected XBehaviourTest() => Execute(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/JustBehave/JustBehave.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net452;netstandard2.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/CustomDictionary.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Behaviour 6 | Configurator 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/JustBehave.NUnit/JustBehave.NUnit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net452;netstandard2.0 4 | JustBehave 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/JustBehave.NUnit/AsyncBehaviourTest.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using NUnit.Framework; 3 | 4 | namespace JustBehave 5 | { 6 | [TestFixture] 7 | public abstract class AsyncBehaviourTest : AsyncBehaviourTestBase 8 | { 9 | [OneTimeSetUp] 10 | public Task Go() => Execute(); 11 | 12 | [OneTimeTearDown] 13 | public virtual Task TeardownAsync() => PostAssertTeardownAsync(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/JustBehave.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [{ 3 | "file_exclude_patterns": [ 4 | "*.bin", 5 | "*.chm", 6 | "*.dll", 7 | "*.exe", 8 | "*.lex", 9 | "*.user" 10 | ], 11 | "folder_exclude_patterns": [ 12 | "bin", 13 | "obj", 14 | "out", 15 | "packages", 16 | "_NCrunch*", 17 | "_ReSharper*" 18 | ], 19 | "path": "." 20 | }], 21 | "settings": { 22 | "tab_size": 2, 23 | "translate_tabs_to_spaces": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/JustBehave/GlobalSuppression.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | [assembly: SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "FxCop's pattern is wrong. http://blog.stephencleary.com/2009/08/third-rule-of-implementing-idisposable.html + http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface?rq=1")] 4 | [assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification = "No they shouldn't.")] 5 | -------------------------------------------------------------------------------- /src/JustBehave.xUnit/JustBehave.xUnit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net452;netstandard2.0 5 | JustBehave 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/JustBehave.xUnit/XAsyncBehaviourTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Xunit; 4 | 5 | namespace JustBehave 6 | { 7 | /// 8 | /// XUnit-based BehaviourTest. 9 | /// 10 | /// 11 | public abstract class XAsyncBehaviourTest : AsyncBehaviourTestBase, IAsyncLifetime 12 | { 13 | public virtual Task InitializeAsync() => Execute(); 14 | 15 | public virtual Task DisposeAsync() => PostAssertTeardownAsync(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/JustBehave.NUnit/BehaviourTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace JustBehave 4 | { 5 | /// 6 | /// NUnit based BehaviourTest. Name kept for backwards compatibility 7 | /// 8 | /// 9 | [TestFixture] 10 | public abstract class BehaviourTest : BehaviourTestBase 11 | { 12 | [OneTimeSetUp] 13 | public void Go() => Execute(); 14 | 15 | [OneTimeTearDown] 16 | public virtual void PostAssertTeardown() {} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2011-2014 JUST EAT plc 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.cs text 7 | *.erb text 8 | *.feature text 9 | *.json text 10 | *.markdown text 11 | *.md text 12 | *.rake text 13 | *.rb text 14 | *.sublime-project text 15 | *.tenjin text 16 | *.txt text 17 | *.yml text 18 | 19 | # Declare files that will always have CRLF line endings on checkout. 20 | *.sln text eol=crlf 21 | 22 | # Denote all files that are truly binary and should not be modified. 23 | *.exe binary 24 | *.gif binary 25 | *.jpeg binary 26 | *.jpg binary 27 | *.png binary 28 | 29 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/GlobalSuppression.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | [assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification = "No they shouldn't.")] 4 | [assembly: SuppressMessage("Microsoft.Design", "CA1053:StaticHolderTypesShouldNotHaveConstructors", Justification = "Tests project", Target = "JustBehave.Tests")] 5 | [assembly: SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Tests project")] 6 | [assembly: SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "FxCop's pattern is wrong. http://blog.stephencleary.com/2009/08/third-rule-of-implementing-idisposable.html + http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface?rq=1")] 7 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/BehaviourTestBaseTests/FrameworkThrowingExceptions/ExceptionIsThrown.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace JustBehave.Tests.BehaviourTestBaseTests.FrameworkThrowingExceptions 5 | { 6 | [TestFixture] 7 | public class ExceptionIsThrown 8 | { 9 | private FakeTestCase _fakeTest; 10 | 11 | [SetUp] 12 | public void SetUp() 13 | { 14 | _fakeTest = new FakeTestCase(() => { throw new Exception("Something bad happened"); }); 15 | } 16 | 17 | [Test] 18 | public void ExceptionNotHandled() 19 | { 20 | var ex = Assert.Throws(() => _fakeTest.Execute()); 21 | 22 | Assert.That(ex.Message, Is.EqualTo("Something bad happened")); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/JustBehave.Tests/Examples/WhenSomethingPasses.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace JustBehave.Tests.Examples 5 | { 6 | public class WhenSomethingPasses : XBehaviourTest 7 | { 8 | private string _result; 9 | 10 | protected override void Given() 11 | { 12 | _result = "food"; 13 | } 14 | 15 | protected override void When() 16 | { 17 | _result = SystemUnderTest.ToString(); 18 | } 19 | 20 | [Fact] 21 | public void ShouldHaveString() 22 | { 23 | _result.ShouldNotBe(null); 24 | } 25 | 26 | [Fact] 27 | public void ShouldHaveChangedFromInitial() 28 | { 29 | _result.ShouldNotBe("food"); 30 | } 31 | } 32 | 33 | // ReSharper disable once ClassNeverInstantiated.Global 34 | public class HappyThing {} 35 | } 36 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/BehaviourTestBaseTests/FrameworkRecordingExceptions/ExceptionIsThrown.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace JustBehave.Tests.BehaviourTestBaseTests.FrameworkRecordingExceptions 5 | { 6 | [TestFixture] 7 | public class ExceptionIsThrown 8 | { 9 | private FakeTestCase _fakeTest; 10 | private Exception _exception; 11 | 12 | [SetUp] 13 | public void SetUp() 14 | { 15 | _exception = new Exception("Something bad happened"); 16 | _fakeTest = new FakeTestCase(() => { throw _exception; }); 17 | _fakeTest.RecordAnyExceptionsThrown(); 18 | } 19 | 20 | [Test] 21 | public void ExceptionCapturedAsThrownException() 22 | { 23 | _fakeTest.Execute(); 24 | 25 | Assert.That(_fakeTest.ThrownException, Is.EqualTo(_exception)); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/JustBehave.Tests/Examples/WhenTestingForExceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Shouldly; 3 | 4 | namespace JustBehave.Tests.Examples 5 | { 6 | public class WhenTestingForExceptions : BehaviourTest 7 | { 8 | protected override void Given() 9 | { 10 | RecordAnyExceptionsThrown(); 11 | } 12 | 13 | protected override void When() 14 | { 15 | BadlyBehaved.TakeADump(); 16 | } 17 | 18 | [Then] 19 | public void ExceptionShouldBeOfExpectedType() 20 | { 21 | ThrownException.ShouldBeAssignableTo(); 22 | } 23 | } 24 | 25 | // ReSharper disable once ClassNeverInstantiated.Global 26 | public class BadlyBehaved 27 | { 28 | public static void TakeADump() 29 | { 30 | throw new InvalidOperationException(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/JustBehave/JustBehave.ncrunchproject: -------------------------------------------------------------------------------- 1 | 2 | false 3 | false 4 | false 5 | false 6 | false 7 | true 8 | true 9 | false 10 | true 11 | true 12 | 60000 13 | 14 | 15 | AutoDetect 16 | 17 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/JustBehave.Tests.ncrunchproject: -------------------------------------------------------------------------------- 1 | 2 | false 3 | false 4 | false 5 | false 6 | false 7 | true 8 | true 9 | false 10 | true 11 | true 12 | 60000 13 | 14 | 15 | AutoDetect 16 | 17 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/BehaviourTestBaseTests/WhenExecuteIsInvokedByTestRunner.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace JustBehave.Tests.BehaviourTestBaseTests 4 | { 5 | [TestFixture] 6 | public class WhenExecuteIsInvokedByTestRunner 7 | { 8 | private FakeTestCase _fakeTest; 9 | 10 | [SetUp] 11 | public void SetUp() 12 | { 13 | _fakeTest = new FakeTestCase(); 14 | _fakeTest.Execute(); 15 | } 16 | 17 | [Test] 18 | public void GivenIsCalled() 19 | { 20 | Assert.That(_fakeTest.GivenExecuted, Is.True); 21 | } 22 | 23 | [Test] 24 | public void WhenIsCalled() 25 | { 26 | Assert.That(_fakeTest.WhenExecuted, Is.True); 27 | } 28 | 29 | [Test] 30 | public void TeardownIsCalled() 31 | { 32 | Assert.That(_fakeTest.TearDownExecuted, Is.True); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 2.0.0.{build} 2 | image: Visual Studio 2017 3 | configuration: Release 4 | before_build: 5 | - dotnet restore src\JustBehave.sln 6 | after_build: 7 | - dotnet pack src\JustBehave.sln -o ..\..\artifacts --no-build 8 | test: 9 | assemblies: 10 | - '**\*.Tests.dll' 11 | artifacts: 12 | - path: ./artifacts/**/*.nupkg 13 | notifications: 14 | - provider: HipChat 15 | room: 'Eng :: Open Source' 16 | auth_token: 17 | secure: eJWABMRPoyfEF9iLzFaTcUEqTc7/64v0FtS1qQe4yhs= 18 | on_build_success: false 19 | on_build_failure: false 20 | on_build_status_changed: false 21 | - provider: Webhook 22 | url: https://webhooks.gitter.im/e/c77e47b2d10f1705b6ff 23 | on_build_success: true 24 | on_build_failure: true 25 | on_build_status_changed: true 26 | deploy: 27 | - provider: NuGet 28 | api_key: 29 | secure: 6MzbzEs4YdJKS67Gio5gEO8mNKmwfC4UHTCmECZ1KOutI6ndm4vAECazmVNB6an7 30 | artifact: /.*\.nupkg/ 31 | on: 32 | APPVEYOR_REPO_TAG: true 33 | -------------------------------------------------------------------------------- /src/JustBehave.ncrunchsolution: -------------------------------------------------------------------------------- 1 | 2 | 1 3 | True 4 | true 5 | true 6 | UseDynamicAnalysis 7 | UseStaticAnalysis 8 | UseStaticAnalysis 9 | UseStaticAnalysis 10 | Run all tests automatically:BFRydWU=;Run all tests manually:BUZhbHNl;Run impacted tests automatically, others manually (experimental!):CklzSW1wYWN0ZWQ=;Run pinned tests automatically, others manually:CElzUGlubmVk 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/JustBehave.v2.ncrunchsolution: -------------------------------------------------------------------------------- 1 | 2 | 1 3 | True 4 | true 5 | true 6 | UseDynamicAnalysis 7 | UseStaticAnalysis 8 | UseStaticAnalysis 9 | UseStaticAnalysis 10 | Run all tests automatically:BFRydWU=;Run all tests manually:BUZhbHNl;Run impacted tests automatically, others manually (experimental!):CklzSW1wYWN0ZWQ=;Run pinned tests automatically, others manually:CElzUGlubmVk 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/Examples/WhenTestingForExceptionsFromConstructors.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Shouldly; 3 | using Xunit; 4 | 5 | namespace JustBehave.Tests.Examples 6 | { 7 | public class WhenTestingForExceptionsFromConstructors : XBehaviourTest 8 | { 9 | protected override BadlyBehavedConstructor CreateSystemUnderTest() 10 | { 11 | return new BadlyBehavedConstructor(); 12 | } 13 | 14 | protected override void Given() 15 | { 16 | RecordAnyExceptionsThrown(); 17 | } 18 | 19 | protected override void When() { } 20 | 21 | [Fact] 22 | public void ShouldSeeException() 23 | { 24 | ThrownException.ShouldBeAssignableTo(); 25 | } 26 | } 27 | 28 | public class BadlyBehavedConstructor 29 | { 30 | public BadlyBehavedConstructor() 31 | { 32 | throw new NotSupportedException(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/AsyncBehaviourTests/WhenTestingForExceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using NUnit.Framework; 4 | using Shouldly; 5 | 6 | namespace JustBehave.Tests.AsyncBehaviourTests 7 | { 8 | public class WhenTestingForExceptions : AsyncBehaviourTest 9 | { 10 | protected override Task Given() 11 | { 12 | RecordAnyExceptionsThrown(); 13 | return Task.CompletedTask; 14 | } 15 | 16 | protected override async Task When() 17 | { 18 | await BadlyBehaved.TakeADump(); 19 | } 20 | 21 | [Then, Test] 22 | public void ExceptionShouldBeOfExpectedType() 23 | { 24 | ThrownException.ShouldBeAssignableTo(); 25 | } 26 | } 27 | 28 | // ReSharper disable once ClassNeverInstantiated.Global 29 | public class BadlyBehaved 30 | { 31 | public static Task TakeADump() 32 | { 33 | throw new InvalidOperationException(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/AsyncBehaviourTests/WhenAnXUnitTestPasses.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Shouldly; 3 | using Xunit; 4 | 5 | namespace JustBehave.Tests.AsyncBehaviourTests 6 | { 7 | public class WhenAnXUnitTestPasses : XAsyncBehaviourTest 8 | { 9 | private string _result; 10 | 11 | protected override Task Given() 12 | { 13 | _result = "food"; 14 | return Task.CompletedTask; 15 | } 16 | 17 | protected override async Task When() 18 | { 19 | _result = await SystemUnderTest.AlwaysHappy(); 20 | } 21 | 22 | [Fact] 23 | public void ShouldHaveString() 24 | { 25 | _result.ShouldNotBe(null); 26 | } 27 | 28 | [Fact] 29 | public void ShouldHaveChangedFromInitial() 30 | { 31 | _result.ShouldNotBe("food"); 32 | } 33 | } 34 | 35 | // ReSharper disable once ClassNeverInstantiated.Global 36 | public class XHappyThing 37 | { 38 | public Task AlwaysHappy() 39 | { 40 | return Task.Run(() => ToString()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/AsyncBehaviourTests/WhenAnNUnitTestPasses.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using NUnit.Framework; 3 | using Shouldly; 4 | 5 | namespace JustBehave.Tests.AsyncBehaviourTests 6 | { 7 | public class WhenAnNunitTestPasses : AsyncBehaviourTest 8 | { 9 | private string _result; 10 | 11 | protected override Task Given() 12 | { 13 | _result = "food"; 14 | return Task.CompletedTask; 15 | } 16 | 17 | protected override async Task When() 18 | { 19 | _result = await SystemUnderTest.AlwaysHappy(); 20 | } 21 | 22 | [Then,Test] 23 | public void ShouldHaveString() 24 | { 25 | _result.ShouldNotBe(null); 26 | } 27 | 28 | [Then,Test] 29 | public void ShouldHaveChangedFromInitial() 30 | { 31 | _result.ShouldNotBe("food"); 32 | } 33 | } 34 | 35 | // ReSharper disable once ClassNeverInstantiated.Global 36 | public class NHappyThing 37 | { 38 | public Task AlwaysHappy() 39 | { 40 | return Task.Run(() => ToString()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/JustBehave/LogExt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using NLog.Targets; 4 | using Shouldly; 5 | 6 | namespace JustBehave 7 | { 8 | public static class LogExt 9 | { 10 | public static void ShouldHaveLogged(this TargetWithLayout target, string message) 11 | { 12 | MemoryTarget(target).Logs.ShouldContain(message); 13 | } 14 | 15 | public static void ShouldHaveLogged(this TargetWithLayout target, Func predicate) 16 | { 17 | var expression = FuncToExpression(predicate); 18 | MemoryTarget(target).Logs.ShouldContain(expression); 19 | } 20 | 21 | private static Expression> FuncToExpression(Func f) 22 | { 23 | return x => f(x); 24 | } 25 | 26 | private static MemoryTarget MemoryTarget(TargetWithLayout target) 27 | { 28 | if (!(target is MemoryTarget memoryTarget)) 29 | { 30 | throw new ArgumentNullException(nameof(target), "target must derive from NLog.Targets.MemoryTarget"); 31 | } 32 | return memoryTarget; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/JustBehave.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.0 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/FakeTestCase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace JustBehave.Tests 4 | { 5 | public class FakeTestCase : BehaviourTestBase 6 | { 7 | private readonly Action _onWhen; 8 | 9 | public bool GivenExecuted { get; private set; } 10 | public bool WhenExecuted { get; private set; } 11 | public bool TearDownExecuted { get; private set; } 12 | 13 | public FakeTestCase(Action onWhen = null) 14 | { 15 | _onWhen = onWhen ?? (()=>{}); 16 | } 17 | 18 | public new void Execute() 19 | { 20 | base.Execute(); 21 | } 22 | 23 | public new void RecordAnyExceptionsThrown() 24 | { 25 | base.RecordAnyExceptionsThrown(); 26 | } 27 | 28 | public new Exception ThrownException 29 | { 30 | get { return base.ThrownException; } 31 | } 32 | 33 | protected override void Given() 34 | { 35 | GivenExecuted = true; 36 | } 37 | 38 | protected override void When() 39 | { 40 | WhenExecuted = true; 41 | _onWhen(); 42 | } 43 | 44 | protected override void Teardown() 45 | { 46 | TearDownExecuted = true; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /release.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true, HelpMessage="The version number to publish, eg 1.2.3. Set this in CI first.")] 3 | [string] $version, 4 | [Parameter(Mandatory=$false, HelpMessage="CI project owner")] 5 | [string] $owner = "justeattech" 6 | ) 7 | 8 | if (($version -eq $null) -or ($version -eq '')) { 9 | # TODO: validate that a tag like this doesn't exist already 10 | throw "Must supply version number in semver format eg 1.2.3" 11 | } 12 | $manifest = get-content "deploy/manifest.json" -raw | ConvertFrom-Json 13 | $ci_name = "je-$($manifest.feature.name)" 14 | $ci_uri = "https://ci.appveyor.com/project/$owner/$ci_name" 15 | $tag = "v$version" 16 | # $release = "release-$version" 17 | write-host "Your current status" -foregroundcolor green 18 | & git status 19 | write-host "Stashing any work and checking out master" -foregroundcolor green 20 | & git stash 21 | & git checkout master 22 | & git pull upstream master --tags 23 | write-host "We'll pause now while you remember to bump the version number in appveyor.yml to match the version you're releasing ($version) ;-)" 24 | write-host " TODO: bounty - do this in code against appveyor's api" -foregroundcolor red 25 | write-host " http://www.appveyor.com/docs/api/projects-builds#update-project" -foregroundcolor red 26 | read-host "hit enter when you've done that..." 27 | write-host "Tagging & branching. tag: $tag / branch: $release" -foregroundcolor green 28 | & git tag -a $tag -m "Release $tag" 29 | & git checkout $tag 30 | write-host "Pushing" -foregroundcolor green 31 | & git push --tags upstream 32 | write-host "Done." 33 | write-host "Check $ci_uri" 34 | & git checkout master 35 | write-host "Putting you back on master branch" -foregroundcolor green 36 | exit 0 37 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/Examples/WhenAssertingAgainstLogs.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NLog; 3 | using NLog.Layouts; 4 | using NLog.Targets; 5 | using Shouldly; 6 | using Xunit; 7 | 8 | namespace JustBehave.Tests.Examples 9 | { 10 | public class WhenAssertingAgainstLogs : XBehaviourTest 11 | { 12 | private string _message; 13 | 14 | protected override void Given() 15 | { 16 | _message = "some message"; 17 | } 18 | 19 | protected override void When() 20 | { 21 | SystemUnderTest.Log.Debug(_message); 22 | } 23 | 24 | [Fact] 25 | public void ShouldBeAbleToAssertLogHappened() 26 | { 27 | ((MemoryTarget)LoggingTarget).Logs.SingleOrDefault(x => x == _message).ShouldNotBeNull(); 28 | } 29 | 30 | [Fact] 31 | public void ShouldBeAbleToUsePredicateExtensionMethod() 32 | { 33 | LoggingTarget.ShouldHaveLogged(x => x == _message); 34 | } 35 | 36 | [Fact] 37 | public void ShouldBeAbleToUseStringExtensionMethod() 38 | { 39 | LoggingTarget.ShouldHaveLogged(_message); 40 | } 41 | 42 | protected override LogLevel ConfigureLogLevel() 43 | { 44 | return LogLevel.Trace; 45 | } 46 | 47 | protected override TargetWithLayout ConfigureLoggingTarget() 48 | { 49 | return new MemoryTarget { Layout = LogLayout()}; 50 | } 51 | 52 | protected override LoggerUnderTest CreateSystemUnderTest() 53 | { 54 | return new LoggerUnderTest {Log = Log}; 55 | } 56 | 57 | protected override Layout LogLayout() 58 | { 59 | return "${message}"; 60 | } 61 | } 62 | 63 | public class LoggerUnderTest 64 | { 65 | public Logger Log { get; set; } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to JustBehave 2 | 3 | ♥ JustBehave and want to get involved? 4 | Great! There are plenty of ways you can help! 5 | 6 | If you find a bug, have a feature request or even want to contribute an enhancement or fix, please follow the below guidelines so that we can help you out and/or get your code merged quickly. 7 | 8 | ## If you find what looks like a bug: 9 | 10 | * Check the [GitHub issue tracker](http://github.com/justeat/JustBehave/issues/) to see if anyone else has reported the issue. 11 | * Make sure you are using the latest version of JustBehave 12 | * If you are still having an issue, create an issue including: 13 | * Information you will need to reproduce and diagnose the problem 14 | 15 | ## If you want to contribute an enhancement or a fix: 16 | 17 | 0. Discuss any major enhancement with the project moderator. 18 | 0. Write your Spec and/or Functional tests. 19 | 0. Write or modify any accompanying documentation. 20 | 0. Ensure that your tests work and your documentation is complete. 21 | 22 | 23 | ### General Contributition Guidelines: 24 | We follow the standard GitHub fork & pull request approach to open source collaboration. 25 | You can find an awesome description on how this works on the [gun.io blog](https://gun.io/blog/how-to-github-fork-branch-and-pull-request/). 26 | 27 | In a nutshell: 28 | 29 | 0. Fork it. 30 | 0. Create your feature branch (`git checkout -b feature/my-new-feature`). 31 | 0. Commit your changes (`git commit -am 'Add some feature'`) and [reference any issues](https://github.com/blog/831-issues-2-0-the-next-generation). 32 | 0. Push to your branch (`git push origin my-new-feature`). 33 | 0. Send a new Pull Request describing what you have done and why, in detail. 34 | 35 | **IMPORTANT**: By submitting a patch, you agree to allow the project owners to 36 | license your work under the the terms of the Apache 2.0 license. A copy of this 37 | license is provided in the root of the repository. 38 | -------------------------------------------------------------------------------- /src/Directory.build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | Just Eat 4 | Just Eat 5 | Copyright 2011-$([System.DateTime]::Now.ToString(yyyy)) Just Eat, Inc. or its affiliates. All Rights Reserved. 6 | A BDD-influenced C# testing library cooked up by Just Eat 7 | latest 8 | embedded 9 | 10 | $(MSBuildProjectName.Contains('Tests')) 11 | 12 | 2 13 | 0 14 | 0 15 | 16 | $(APPVEYOR_BUILD_NUMBER) 17 | $(BUILD_NUMBER) 18 | 0 19 | 20 | 21 | -beta 22 | 23 | $(PrereleaseLabel)-$(BuildNumber) 24 | 25 | 26 | $(Major).0.0.0 27 | $(Major).$(Minor).$(Revision).$(BuildNumber) 28 | $(Major).$(Minor).$(Revision)$(BuildSuffix) 29 | $(Major).$(Minor).$(Revision)$(BuildSuffix) 30 | 31 | true 32 | true 33 | $(MSBuildThisFileDirectory)justeat-oss.snk 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/JustBehave.Tests/Examples/WhenTestingSomethingWithDependencies.cs: -------------------------------------------------------------------------------- 1 | using AutoFixture; 2 | using AutoFixture.AutoNSubstitute; 3 | using NSubstitute; 4 | using Shouldly; 5 | using Xunit; 6 | 7 | namespace JustBehave.Tests.Examples 8 | { 9 | public class WhenTestingSomethingWithDependencies : XBehaviourTest 10 | { 11 | private ISomethingElse _fake; 12 | private string _result; 13 | private string _speech; 14 | 15 | protected override void Given() 16 | { 17 | _result = "bar"; 18 | _fake = Fixture.Freeze(); 19 | _fake.SayHello().Returns("hi"); 20 | } 21 | 22 | protected override void When() 23 | { 24 | _result = SomethingUnderTest.Food(); 25 | _speech = SystemUnderTest.SomethingElse.SayHello(); 26 | } 27 | 28 | protected override void CustomizeAutoFixture(IFixture fixture) 29 | { 30 | fixture.Customize(new AutoNSubstituteCustomization{ ConfigureMembers = true }); 31 | } 32 | 33 | [Fact] 34 | public void ShouldReadFood() 35 | { 36 | _result.ShouldBe("food"); 37 | } 38 | 39 | [Fact] 40 | public void ShouldSupplyDependency() 41 | { 42 | SystemUnderTest.SomethingElse.ShouldNotBe(null); 43 | } 44 | 45 | [Fact] 46 | public void ShouldBeAbleToReturnSameInstanceOfDependency() 47 | { 48 | var expected = Fixture.Create().ToString(); 49 | var actual = SystemUnderTest.SomethingElse.ToString(); 50 | actual.ShouldBe(expected); 51 | } 52 | 53 | [Fact] 54 | public void ShouldBeAbleToRunExpectationAndVerify() 55 | { 56 | _speech.ShouldBe("hi"); 57 | } 58 | } 59 | 60 | public class SomethingUnderTest 61 | { 62 | private readonly ISomethingElse _somethingElse; 63 | 64 | public SomethingUnderTest(ISomethingElse somethingElse) 65 | { 66 | _somethingElse = somethingElse; 67 | } 68 | 69 | public ISomethingElse SomethingElse 70 | { 71 | get { return _somethingElse; } 72 | } 73 | 74 | public static string Food() 75 | { 76 | return "food"; 77 | } 78 | } 79 | 80 | public interface ISomethingElse 81 | { 82 | string SayHello(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/JustBehave.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.27004.2008 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JustBehave", "JustBehave\JustBehave.csproj", "{226465BD-C58A-4723-AA6E-8C48ABBAD4C7}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JustBehave.Tests", "JustBehave.Tests\JustBehave.Tests.csproj", "{FB7B5C17-73F9-45D6-901B-5BEDD314DCF3}" 8 | EndProject 9 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JustBehave.NUnit", "JustBehave.NUnit\JustBehave.NUnit.csproj", "{9F1D016F-F3AB-426D-B7B5-2830917CB94E}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JustBehave.xUnit", "JustBehave.xUnit\JustBehave.xUnit.csproj", "{27392297-4914-4C00-A754-F777F51FAD86}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {226465BD-C58A-4723-AA6E-8C48ABBAD4C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {226465BD-C58A-4723-AA6E-8C48ABBAD4C7}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {226465BD-C58A-4723-AA6E-8C48ABBAD4C7}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {226465BD-C58A-4723-AA6E-8C48ABBAD4C7}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {FB7B5C17-73F9-45D6-901B-5BEDD314DCF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {FB7B5C17-73F9-45D6-901B-5BEDD314DCF3}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {FB7B5C17-73F9-45D6-901B-5BEDD314DCF3}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {FB7B5C17-73F9-45D6-901B-5BEDD314DCF3}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {9F1D016F-F3AB-426D-B7B5-2830917CB94E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {9F1D016F-F3AB-426D-B7B5-2830917CB94E}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {9F1D016F-F3AB-426D-B7B5-2830917CB94E}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {9F1D016F-F3AB-426D-B7B5-2830917CB94E}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {27392297-4914-4C00-A754-F777F51FAD86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {27392297-4914-4C00-A754-F777F51FAD86}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {27392297-4914-4C00-A754-F777F51FAD86}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {27392297-4914-4C00-A754-F777F51FAD86}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | GlobalSection(ExtensibilityGlobals) = postSolution 40 | SolutionGuid = {B592ABE0-8408-4E77-A937-FE0B6DCC611F} 41 | EndGlobalSection 42 | GlobalSection(NDepend) = preSolution 43 | Project = ".\JustBehave.ndproj" 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /src/JustBehave/BehaviourTestBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using AutoFixture; 4 | using NLog; 5 | using NLog.Config; 6 | using NLog.Layouts; 7 | using NLog.Targets; 8 | 9 | namespace JustBehave 10 | { 11 | public abstract class BehaviourTestBase 12 | { 13 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 14 | protected BehaviourTestBase() 15 | { 16 | ExceptionMode = ExceptionMode.Throw; 17 | LoggingTarget = ConfigureLoggingTarget(); 18 | LogLevel = ConfigureLogLevel(); 19 | SimpleConfigurator.ConfigureForTargetLogging(LoggingTarget, LogLevel); 20 | Log = LogManager.GetCurrentClassLogger(); 21 | 22 | Fixture = new Fixture(); 23 | CustomizeAutoFixture(Fixture); 24 | } 25 | // ReSharper restore DoNotCallOverridableMethodsInConstructor 26 | 27 | protected IFixture Fixture { get; private set; } 28 | protected Logger Log { get; private set; } 29 | protected TargetWithLayout LoggingTarget { get; private set; } 30 | protected TSystemUnderTest SystemUnderTest { get; private set; } 31 | protected Exception ThrownException { get; private set; } 32 | private ExceptionMode ExceptionMode { get; set; } 33 | private LogLevel LogLevel { get; set; } 34 | 35 | protected virtual LogLevel ConfigureLogLevel() 36 | { 37 | return LogLevel.Warn; 38 | } 39 | 40 | protected virtual TargetWithLayout ConfigureLoggingTarget() 41 | { 42 | return new ColoredConsoleTarget {Layout = LogLayout()}; 43 | } 44 | 45 | protected virtual TSystemUnderTest CreateSystemUnderTest() 46 | { 47 | return Fixture.Create(); 48 | } 49 | 50 | protected virtual void CustomizeAutoFixture(IFixture fixture) {} 51 | 52 | protected void Execute() 53 | { 54 | Given(); 55 | 56 | try 57 | { 58 | SystemUnderTest = CreateSystemUnderTest(); 59 | When(); 60 | } 61 | catch (Exception ex) 62 | { 63 | if (ExceptionMode == ExceptionMode.Record) 64 | { 65 | ThrownException = ex; 66 | } 67 | else 68 | { 69 | throw; 70 | } 71 | } 72 | finally 73 | { 74 | Teardown(); 75 | } 76 | } 77 | 78 | protected abstract void Given(); 79 | 80 | protected virtual Layout LogLayout() 81 | { 82 | return "${message}"; 83 | } 84 | 85 | protected void RecordAnyExceptionsThrown() 86 | { 87 | ExceptionMode = ExceptionMode.Record; 88 | } 89 | 90 | protected virtual void Teardown() {} 91 | 92 | [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", Justification = "When really is the best name for this message")] 93 | protected abstract void When(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/JustBehave/AsyncBehaviourTestBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Threading.Tasks; 4 | using AutoFixture; 5 | using NLog; 6 | using NLog.Config; 7 | using NLog.Layouts; 8 | using NLog.Targets; 9 | 10 | namespace JustBehave 11 | { 12 | public abstract class AsyncBehaviourTestBase 13 | { 14 | private static readonly Task CompletedTask = Task.FromResult(true); 15 | // ReSharper disable DoNotCallOverridableMethodsInConstructor 16 | protected AsyncBehaviourTestBase() 17 | { 18 | ExceptionMode = ExceptionMode.Throw; 19 | LoggingTarget = ConfigureLoggingTarget(); 20 | LogLevel = ConfigureLogLevel(); 21 | SimpleConfigurator.ConfigureForTargetLogging(LoggingTarget, LogLevel); 22 | Log = LogManager.GetCurrentClassLogger(); 23 | 24 | Fixture = new Fixture(); 25 | CustomizeAutoFixture(Fixture); 26 | } 27 | // ReSharper restore DoNotCallOverridableMethodsInConstructor 28 | 29 | // ReSharper disable MemberCanBePrivate.Global 30 | protected IFixture Fixture { get; private set; } 31 | protected Logger Log { get; private set; } 32 | protected TargetWithLayout LoggingTarget { get; private set; } 33 | // ReSharper restore MemberCanBePrivate.Global 34 | protected TSystemUnderTest SystemUnderTest { get; private set; } 35 | protected Exception ThrownException { get; private set; } 36 | private ExceptionMode ExceptionMode { get; set; } 37 | private LogLevel LogLevel { get; set; } 38 | 39 | protected virtual LogLevel ConfigureLogLevel() 40 | { 41 | return LogLevel.Warn; 42 | } 43 | 44 | protected virtual TargetWithLayout ConfigureLoggingTarget() 45 | { 46 | return new ColoredConsoleTarget { Layout = LogLayout() }; 47 | } 48 | 49 | protected virtual Task CreateSystemUnderTestAsync() 50 | { 51 | return Task.FromResult(Fixture.Create()); 52 | } 53 | 54 | protected virtual void CustomizeAutoFixture(IFixture fixture) { } 55 | 56 | protected async Task Execute() 57 | { 58 | await Given().ConfigureAwait(false); 59 | 60 | try 61 | { 62 | SystemUnderTest = await CreateSystemUnderTestAsync().ConfigureAwait(false); 63 | await When().ConfigureAwait(false); 64 | } 65 | catch (Exception ex) 66 | { 67 | if (ExceptionMode == ExceptionMode.Record) 68 | { 69 | ThrownException = ex; 70 | } 71 | else 72 | { 73 | throw; 74 | } 75 | } 76 | finally 77 | { 78 | Teardown(); 79 | } 80 | } 81 | 82 | protected abstract Task Given(); 83 | 84 | protected virtual Layout LogLayout() 85 | { 86 | return "${message}"; 87 | } 88 | 89 | protected virtual Task PostAssertTeardownAsync() => CompletedTask; 90 | 91 | protected void RecordAnyExceptionsThrown() 92 | { 93 | ExceptionMode = ExceptionMode.Record; 94 | } 95 | 96 | protected virtual void Teardown() { } 97 | 98 | [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", Justification = "When really is the best name for this message")] 99 | protected abstract Task When(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JustBehave 2 | ========== 3 | 4 | [![Join the chat at https://gitter.im/justeat/JustBehave](https://badges.gitter.im/justeat/JustBehave.svg)](https://gitter.im/justeat/JustBehave?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | _A BDD-influenced C# testing library cooked up by JUST EAT_ 6 | 7 | --- 8 | 9 | Appveyor: ![Appveyor](https://img.shields.io/appveyor/ci/justeattech/justbehave.svg) 10 | 11 | * Introduction 12 | * Installation 13 | * Getting Started 14 | * Documentation 15 | * Contributing 16 | * Copyright 17 | 18 | JustBehave is a small .NET library that helps you structure your C# tests into BDD-style contexts and scenarios. 19 | It supports both **NUnit** and **XUnit** and depends on **AutoFixture** for automatic dependency construction using your mocking framework of choice. 20 | 21 | JustBehave was written to ensure that our internal tests followed a consistent and sane BDD pattern, without relying on frameworks like SpecFlow and the Gherkin language. Tests written using JustBehave are structured and organised, without requiring additional tooling or plugins. 22 | 23 | 24 | ## Installation 25 | 26 | Pre-requisites: The project is built in .net v4.0. 27 | 28 | * From source: https://github.com/justeat/JustBehave 29 | * By hand: https://www.nuget.org/packages/JustBehave 30 | 31 | Via NuGet: 32 | 33 | PM> Install-Package JustBehave 34 | 35 | 36 | ## Getting Started 37 | 38 | Once you have the package installed into your test project, along with your test framework of choice, a standard JustBehave test file will look like this using XUnit: 39 | ```csharp 40 | //public class TestClassNamedAfterABddContext : XBehaviourTest // XUnit 41 | public class TestClassNamedAfterABddContext : BehaviourTest // NUnit 42 | { 43 | private string _input; 44 | private string _result; 45 | 46 | protected override void Given() 47 | { 48 | _input = "my input"; 49 | } 50 | 51 | protected override void When() 52 | { 53 | _result = SystemUnderTest.CallingAMethod(_input); 54 | } 55 | 56 | [Then] 57 | public void ReturnsSomething() 58 | { 59 | _result.ShouldBe("something"); 60 | } 61 | } 62 | ``` 63 | A full set of tested examples are provided in the repository in the project **JustBehave.Tests** in the **Examples** namespace. 64 | 65 | ## Documentation 66 | 67 | * Important classes and attributes 68 | * Structuring Contexts and Scenarios 69 | * Handling and Testing Exceptions 70 | * Testing classes with dependencies 71 | 72 | ### Important classes and attributes 73 | 74 | The core of JustBehave is built upon a few small classes: 75 | 76 | * `BehaviourTest` - inherited for an **NUnit** test 77 | * `XBehaviourTest` - inherited for an **XUnit** test 78 | * `ThenAttribute` - used to annotate your **Then** conditions for the nunit testing framework 79 | * when using xunit, use `FactAttribute` as normal 80 | 81 | This leads to test classes that follow the convention: 82 | ```csharp 83 | public class TestClassNamedAfterABddContext : BehaviourTest 84 | { 85 | protected override void Given(){ /*...*/ } 86 | protected override void When(){ /*...*/ } 87 | [Then] public void Assertion1(){ /*...*/ } 88 | [Then] public void Assertion2(){ /*...*/ } 89 | } 90 | ``` 91 | The NUnit `TestFixtureAttribute` is optional and implemented on the base of our NUnit BehaviourTest classes. 92 | 93 | ### Structuring Contexts and Scenarios 94 | 95 | The core of JustBehave is a base class for your tests that enforces a **"Given, When, Then"** pattern. Each test file represents a single context with a *Given*, a *When*, and multiple *Then* assertions. 96 | 97 | Broader tests are constructed by **inheriting from previous test classes**, and overriding the *Given* or *When* steps, while adding additional *Then* conditions to construct scenarios. Expect to use namespaces to group related scenarios, while **giving your test classes names that represent their context**. 98 | 99 | For example, when testing some payment infrastructure, expect to end up with a set of files like this: 100 | 101 | /Tests/Payments/WhenIMakeAPayment.cs 102 | /Tests/Payments/AndMyPaymentIsRejected.cs (inherits from WhenIMakeAPayment.cs) 103 | /Tests/Payments/AndMyPaymentIsAccepted.cs (inherits from WhenIMakeAPayment.cs) 104 | 105 | By following this style, you'll end up with a ReSharper test runner that looks like this: 106 | 107 | ![test runner following bdd conventions](test-screenshot.png) 108 | 109 | ### Handling and Testing Exceptions 110 | 111 | If you want to assert on thrown exceptions, you setup your Given() step like this: 112 | ```csharp 113 | protected override void Given() 114 | { 115 | RecordAnyExceptionsThrown(); 116 | } 117 | ``` 118 | Any exceptions thrown will then be available in your Then steps for you to assert on: 119 | ```csharp 120 | [Then] 121 | public void ShouldSeeException() 122 | { 123 | ThrownException.ShouldBeTypeOf(); 124 | } 125 | ``` 126 | ### Testing classes with dependencies 127 | 128 | In order for JustBehave to construct your dependency graphs, you must either: 129 | 130 | * Manually construct your system under test 131 | * Configure AutoFixture and a mocking framework to auto-mock your dependencies 132 | 133 | To override construction of the system under test, you need to override `CreateSystemUnderTest()` and return a valid instance: 134 | 135 | ```csharp 136 | protected override SomethingUnderTest CreateSystemUnderTest() 137 | { 138 | return new SomethingUnderTest(); 139 | } 140 | ``` 141 | 142 | Alternatively, to configure AutoFixture, you should override `CustomizeAutoFixture()` providing a valid `AutoFixture` customisation: 143 | 144 | ```csharp 145 | protected override void CustomizeAutoFixture(Fixture fixture) 146 | { 147 | fixture.Customize(new AutoRhinoMockCustomization()); 148 | // You can add more customisations by adding the NuGet packages for 149 | // Ploeh.AutoFixture.Auto**PopularMockingFramework** and hooking them up 150 | } 151 | ``` 152 | 153 | ## Contributing 154 | 155 | If you find a bug, have a feature request or even want to contribute an enhancement or fix, please follow the contributing guidelines included in the repository. 156 | 157 | 158 | ## Copyright 159 | 160 | Copyright 2011-2014 Just Eat, Inc. or its affiliates. All Rights Reserved. 161 | 162 | Licensed under the Apache License, Version 2.0 (the "License"). You 163 | may not use this file except in compliance with the License. A copy of 164 | the License is located in the LICENSE file in this repository. 165 | 166 | This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 167 | CONDITIONS OF ANY KIND, either express or implied. See the License 168 | for the specific language governing permissions and limitations under 169 | the License. 170 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/visualstudio,visualstudiocode 3 | 4 | ### VisualStudioCode ### 5 | .vscode/* 6 | !.vscode/settings.json 7 | !.vscode/tasks.json 8 | !.vscode/launch.json 9 | !.vscode/extensions.json 10 | .history 11 | 12 | ### VisualStudio ### 13 | ## Ignore Visual Studio temporary files, build results, and 14 | ## files generated by popular Visual Studio add-ons. 15 | ## 16 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 17 | 18 | # User-specific files 19 | *.suo 20 | *.user 21 | *.userosscache 22 | *.sln.docstates 23 | *.idea 24 | project.lock.json 25 | .vs/ 26 | 27 | # User-specific files (MonoDevelop/Xamarin Studio) 28 | *.userprefs 29 | 30 | # Build results 31 | [Dd]ebug/ 32 | [Dd]ebugPublic/ 33 | [Rr]elease/ 34 | [Rr]eleases/ 35 | x64/ 36 | x86/ 37 | bld/ 38 | [Bb]in/ 39 | [Oo]bj/ 40 | [Ll]og/ 41 | 42 | # Visual Studio 2015 cache/options directory 43 | .vs/ 44 | # Uncomment if you have tasks that create the project's static files in wwwroot 45 | #wwwroot/ 46 | 47 | # MSTest test Results 48 | [Tt]est[Rr]esult*/ 49 | [Bb]uild[Ll]og.* 50 | 51 | # NUNIT 52 | *.VisualState.xml 53 | TestResult.xml 54 | 55 | # Build Results of an ATL Project 56 | [Dd]ebugPS/ 57 | [Rr]eleasePS/ 58 | dlldata.c 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | **/Properties/launchSettings.json 65 | 66 | *_i.c 67 | *_p.c 68 | *_i.h 69 | *.ilk 70 | *.meta 71 | *.obj 72 | *.pch 73 | *.pdb 74 | *.pgc 75 | *.pgd 76 | *.rsp 77 | *.sbr 78 | *.tlb 79 | *.tli 80 | *.tlh 81 | *.tmp 82 | *.tmp_proj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # Visual Studio code coverage results 132 | *.coverage 133 | *.coveragexml 134 | 135 | # NCrunch 136 | _NCrunch_* 137 | .*crunch*.local.xml 138 | nCrunchTemp_* 139 | 140 | # MightyMoose 141 | *.mm.* 142 | AutoTest.Net/ 143 | 144 | # Web workbench (sass) 145 | .sass-cache/ 146 | 147 | # Installshield output folder 148 | [Ee]xpress/ 149 | 150 | # DocProject is a documentation generator add-in 151 | DocProject/buildhelp/ 152 | DocProject/Help/*.HxT 153 | DocProject/Help/*.HxC 154 | DocProject/Help/*.hhc 155 | DocProject/Help/*.hhk 156 | DocProject/Help/*.hhp 157 | DocProject/Help/Html2 158 | DocProject/Help/html 159 | 160 | # Click-Once directory 161 | publish/ 162 | 163 | # Publish Web Output 164 | *.[Pp]ublish.xml 165 | *.azurePubxml 166 | # TODO: Uncomment the next line to ignore your web deploy settings. 167 | # By default, sensitive information, such as encrypted password 168 | # should be stored in the .pubxml.user file. 169 | #*.pubxml 170 | *.pubxml.user 171 | *.publishproj 172 | 173 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 174 | # checkin your Azure Web App publish settings, but sensitive information contained 175 | # in these scripts will be unencrypted 176 | PublishScripts/ 177 | 178 | # NuGet Packages 179 | *.nupkg 180 | # The packages folder can be ignored because of Package Restore 181 | **/packages/* 182 | # except build/, which is used as an MSBuild target. 183 | !**/packages/build/ 184 | # Uncomment if necessary however generally it will be regenerated when needed 185 | #!**/packages/repositories.config 186 | # NuGet v3's project.json files produces more ignorable files 187 | *.nuget.props 188 | *.nuget.targets 189 | 190 | # Microsoft Azure Build Output 191 | csx/ 192 | *.build.csdef 193 | 194 | # Microsoft Azure Emulator 195 | ecf/ 196 | rcf/ 197 | 198 | # Windows Store app package directories and files 199 | AppPackages/ 200 | BundleArtifacts/ 201 | Package.StoreAssociation.xml 202 | _pkginfo.txt 203 | 204 | # Visual Studio cache files 205 | # files ending in .cache can be ignored 206 | *.[Cc]ache 207 | # but keep track of directories ending in .cache 208 | !*.[Cc]ache/ 209 | 210 | # Others 211 | ClientBin/ 212 | ~$* 213 | *~ 214 | *.dbmdl 215 | *.dbproj.schemaview 216 | *.jfm 217 | *.pfx 218 | *.publishsettings 219 | orleans.codegen.cs 220 | 221 | # Since there are multiple workflows, uncomment next line to ignore bower_components 222 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 223 | #bower_components/ 224 | 225 | # RIA/Silverlight projects 226 | Generated_Code/ 227 | 228 | # Backup & report files from converting an old project file 229 | # to a newer Visual Studio version. Backup files are not needed, 230 | # because we have git ;-) 231 | _UpgradeReport_Files/ 232 | Backup*/ 233 | UpgradeLog*.XML 234 | UpgradeLog*.htm 235 | 236 | # SQL Server files 237 | *.mdf 238 | *.ldf 239 | *.ndf 240 | 241 | # Business Intelligence projects 242 | *.rdl.data 243 | *.bim.layout 244 | *.bim_*.settings 245 | 246 | # Microsoft Fakes 247 | FakesAssemblies/ 248 | 249 | # GhostDoc plugin setting file 250 | *.GhostDoc.xml 251 | 252 | # Node.js Tools for Visual Studio 253 | .ntvs_analysis.dat 254 | node_modules/ 255 | 256 | # Typescript v1 declaration files 257 | typings/ 258 | 259 | # Visual Studio 6 build log 260 | *.plg 261 | 262 | # Visual Studio 6 workspace options file 263 | *.opt 264 | 265 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 266 | *.vbw 267 | 268 | # Visual Studio LightSwitch build output 269 | **/*.HTMLClient/GeneratedArtifacts 270 | **/*.DesktopClient/GeneratedArtifacts 271 | **/*.DesktopClient/ModelManifest.xml 272 | **/*.Server/GeneratedArtifacts 273 | **/*.Server/ModelManifest.xml 274 | _Pvt_Extensions 275 | 276 | # Paket dependency manager 277 | .paket/paket.exe 278 | paket-files/ 279 | 280 | # FAKE - F# Make 281 | .fake/ 282 | 283 | # JetBrains Rider 284 | .idea/ 285 | *.sln.iml 286 | 287 | # CodeRush 288 | .cr/ 289 | 290 | # Python Tools for Visual Studio (PTVS) 291 | __pycache__/ 292 | *.pyc 293 | 294 | # Cake - Uncomment if you are using it 295 | # tools/** 296 | # !tools/packages.config 297 | 298 | # Telerik's JustMock configuration file 299 | *.jmconfig 300 | 301 | # BizTalk build output 302 | *.btp.cs 303 | *.btm.cs 304 | *.odx.cs 305 | *.xsd.cs 306 | 307 | ### VisualStudio Patch ### 308 | # By default, sensitive information, such as encrypted password 309 | # should be stored in the .pubxml.user file. 310 | 311 | # End of https://www.gitignore.io/api/visualstudio,visualstudiocode -------------------------------------------------------------------------------- /src/JustBehave.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | <?xml version="1.0" encoding="utf-16"?> 3 | <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> 4 | <TypePattern Priority="2000" DisplayName="Type Pattern"> 5 | <TypePattern.Match> 6 | <And> 7 | <Kind Is="Interface" /> 8 | <Or> 9 | <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> 10 | <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> 11 | </Or> 12 | </And> 13 | </TypePattern.Match> 14 | </TypePattern> 15 | <TypePattern Priority="2000" DisplayName="Type Pattern"> 16 | <TypePattern.Match> 17 | <And> 18 | <Or> 19 | <Kind Is="Struct" /> 20 | <Kind Is="Class" /> 21 | </Or> 22 | <HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" /> 23 | </And> 24 | </TypePattern.Match> 25 | </TypePattern> 26 | <TypePattern Priority="2000" DisplayName="Type Pattern"> 27 | <TypePattern.Match> 28 | <And> 29 | <Kind Is="Class" /> 30 | <Name Is=".*NativeMethods" /> 31 | </And> 32 | </TypePattern.Match> 33 | </TypePattern> 34 | <TypePattern Priority="1000" DisplayName="Type Pattern"> 35 | <TypePattern.Match> 36 | <Or> 37 | <Kind Is="Class" /> 38 | <Kind Is="Struct" /> 39 | <Kind Is="Interface" /> 40 | </Or> 41 | </TypePattern.Match> 42 | <Entry DisplayName="Entry"> 43 | <Entry.Match> 44 | <Or> 45 | <Kind Is="Constant" /> 46 | <Kind Is="Field" /> 47 | </Or> 48 | </Entry.Match> 49 | <Entry.SortBy> 50 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 51 | <Kind Order="Constant Field" /> 52 | <Readonly /> 53 | <Static /> 54 | <Name /> 55 | </Entry.SortBy> 56 | </Entry> 57 | <Entry Priority="200" DisplayName="Entry"> 58 | <Entry.Match> 59 | <Or> 60 | <Kind Is="Constructor" /> 61 | <Kind Is="Destructor" /> 62 | </Or> 63 | </Entry.Match> 64 | <Entry.SortBy> 65 | <Static /> 66 | <Kind Order="Constructor Destructor" /> 67 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 68 | </Entry.SortBy> 69 | </Entry> 70 | <Entry DisplayName="Entry"> 71 | <Entry.Match> 72 | <Kind Is="Delegate" /> 73 | </Entry.Match> 74 | <Entry.SortBy> 75 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 76 | <Static /> 77 | <Name /> 78 | </Entry.SortBy> 79 | </Entry> 80 | <Entry DisplayName="Entry"> 81 | <Entry.Match> 82 | <And> 83 | <Kind Is="Event" /> 84 | <Access Is="Public" /> 85 | </And> 86 | </Entry.Match> 87 | <Entry.SortBy> 88 | <Access Order="Public" /> 89 | <Static /> 90 | <Name /> 91 | </Entry.SortBy> 92 | </Entry> 93 | <Entry DisplayName="Entry"> 94 | <Entry.Match> 95 | <And> 96 | <Kind Is="Event" /> 97 | <ImplementsInterface /> 98 | </And> 99 | </Entry.Match> 100 | <Entry.SortBy> 101 | <ImplementsInterface Immediate="True" /> 102 | <Name /> 103 | </Entry.SortBy> 104 | </Entry> 105 | <Entry DisplayName="Entry"> 106 | <Entry.Match> 107 | <Kind Is="Event" /> 108 | </Entry.Match> 109 | <Entry.SortBy> 110 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 111 | <Static /> 112 | <Name /> 113 | </Entry.SortBy> 114 | </Entry> 115 | <Entry DisplayName="Entry"> 116 | <Entry.Match> 117 | <Kind Is="Enum" /> 118 | </Entry.Match> 119 | <Entry.SortBy> 120 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 121 | <Name /> 122 | </Entry.SortBy> 123 | </Entry> 124 | <Entry DisplayName="Entry"> 125 | <Entry.Match> 126 | <Kind Is="Interface" /> 127 | </Entry.Match> 128 | <Entry.SortBy> 129 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 130 | <Name /> 131 | </Entry.SortBy> 132 | </Entry> 133 | <Entry DisplayName="Entry"> 134 | <Entry.Match> 135 | <And> 136 | <Kind Is="Property" /> 137 | <Access Is="Public" /> 138 | </And> 139 | </Entry.Match> 140 | <Entry.SortBy> 141 | <Access Order="Public" /> 142 | <Static /> 143 | <Name /> 144 | </Entry.SortBy> 145 | </Entry> 146 | <Entry DisplayName="Entry"> 147 | <Entry.Match> 148 | <And> 149 | <Kind Is="Property" /> 150 | <ImplementsInterface /> 151 | </And> 152 | </Entry.Match> 153 | <Entry.SortBy> 154 | <ImplementsInterface Immediate="True" /> 155 | <Name /> 156 | </Entry.SortBy> 157 | </Entry> 158 | <Entry DisplayName="Entry"> 159 | <Entry.Match> 160 | <Kind Is="Property" /> 161 | </Entry.Match> 162 | <Entry.SortBy> 163 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 164 | <Static /> 165 | <Name /> 166 | </Entry.SortBy> 167 | </Entry> 168 | <Entry Priority="1000" DisplayName="Entry"> 169 | <Entry.Match> 170 | <And> 171 | <Kind Is="Indexer" /> 172 | <Access Is="Public" /> 173 | </And> 174 | </Entry.Match> 175 | <Entry.SortBy> 176 | <Access Order="Public" /> 177 | <Static /> 178 | <Name /> 179 | </Entry.SortBy> 180 | </Entry> 181 | <Entry Priority="1000" DisplayName="Entry"> 182 | <Entry.Match> 183 | <And> 184 | <Kind Is="Indexer" /> 185 | <ImplementsInterface /> 186 | </And> 187 | </Entry.Match> 188 | <Entry.SortBy> 189 | <ImplementsInterface Immediate="True" /> 190 | <Name /> 191 | </Entry.SortBy> 192 | </Entry> 193 | <Entry Priority="1000" DisplayName="Entry"> 194 | <Entry.Match> 195 | <Kind Is="Indexer" /> 196 | </Entry.Match> 197 | <Entry.SortBy> 198 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 199 | <Static /> 200 | <Name /> 201 | </Entry.SortBy> 202 | </Entry> 203 | <Entry DisplayName="Entry"> 204 | <Entry.Match> 205 | <And> 206 | <Kind Is="Method" /> 207 | <Access Is="Public" /> 208 | </And> 209 | </Entry.Match> 210 | <Entry.SortBy> 211 | <Access Order="Public" /> 212 | <Static /> 213 | <Name /> 214 | </Entry.SortBy> 215 | </Entry> 216 | <Entry DisplayName="Entry"> 217 | <Entry.Match> 218 | <And> 219 | <Kind Is="Method" /> 220 | <ImplementsInterface /> 221 | </And> 222 | </Entry.Match> 223 | <Entry.SortBy> 224 | <ImplementsInterface Immediate="True" /> 225 | <Name /> 226 | </Entry.SortBy> 227 | </Entry> 228 | <Entry DisplayName="Entry"> 229 | <Entry.Match> 230 | <Kind Is="Method" /> 231 | </Entry.Match> 232 | <Entry.SortBy> 233 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 234 | <Static /> 235 | <Name /> 236 | </Entry.SortBy> 237 | </Entry> 238 | <Entry DisplayName="Entry"> 239 | <Entry.Match> 240 | <Kind Is="Operator" /> 241 | </Entry.Match> 242 | <Entry.SortBy> 243 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 244 | <Static /> 245 | <Name /> 246 | </Entry.SortBy> 247 | </Entry> 248 | <Entry Priority="600" DisplayName="Entry"> 249 | <Entry.Match> 250 | <Kind Is="Struct" /> 251 | </Entry.Match> 252 | <Entry.SortBy> 253 | <Static /> 254 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 255 | <Name /> 256 | </Entry.SortBy> 257 | </Entry> 258 | <Entry Priority="700" DisplayName="Entry"> 259 | <Entry.Match> 260 | <Kind Is="Class" /> 261 | </Entry.Match> 262 | <Entry.SortBy> 263 | <Static /> 264 | <Access Order="Public Internal ProtectedInternal Protected Private" /> 265 | <Name /> 266 | </Entry.SortBy> 267 | </Entry> 268 | <Entry DisplayName="Entry" /> 269 | </TypePattern> 270 | <TypePattern Priority="100" DisplayName="Type Pattern"> 271 | <TypePattern.Match> 272 | <And> 273 | <Kind Is="Class" /> 274 | <Or> 275 | <HasAttribute Name="Machine.Specifications.SubjectAttribute" Inherited="True" /> 276 | <Name Is="^when_.+" IgnoreCase="True" /> 277 | </Or> 278 | </And> 279 | </TypePattern.Match> 280 | <Entry DisplayName="Entry"> 281 | <Entry.Match> 282 | <And> 283 | <Kind Is="Field" /> 284 | <Or> 285 | <Access Is="Protected" /> 286 | <Static /> 287 | </Or> 288 | </And> 289 | </Entry.Match> 290 | </Entry> 291 | <Entry DisplayName="Entry"> 292 | <Entry.Match> 293 | <And> 294 | <Kind Is="Field" /> 295 | <Name Is="^context(_once)?$" IgnoreCase="True" /> 296 | </And> 297 | </Entry.Match> 298 | </Entry> 299 | <Entry DisplayName="Entry"> 300 | <Entry.Match> 301 | <And> 302 | <Kind Is="Field" /> 303 | <Name Is="^of$" IgnoreCase="True" /> 304 | </And> 305 | </Entry.Match> 306 | </Entry> 307 | <Entry DisplayName="Entry"> 308 | <Entry.Match> 309 | <And> 310 | <Kind Is="Field" /> 311 | <Name Is="^after(_all)?$" IgnoreCase="True" /> 312 | </And> 313 | </Entry.Match> 314 | </Entry> 315 | <Entry DisplayName="Entry"> 316 | <Entry.Match> 317 | <And> 318 | <Kind Is="Field" /> 319 | <Name Is="^should_.*$" IgnoreCase="True" /> 320 | </And> 321 | </Entry.Match> 322 | </Entry> 323 | <Entry DisplayName="Entry"> 324 | <Entry.Match> 325 | <And> 326 | <Kind Is="Field" /> 327 | <Not> 328 | <Static /> 329 | </Not> 330 | </And> 331 | </Entry.Match> 332 | </Entry> 333 | <Entry DisplayName="Entry" /> 334 | </TypePattern> 335 | </Patterns> 336 | <?xml version="1.0" encoding="utf-8" ?> 337 | 338 | <!-- 339 | I. Overall 340 | 341 | I.1 Each pattern can have <Match>....</Match> element. For the given type declaration, the pattern with the match, evaluated to 'true' with the largest weight, will be used 342 | I.2 Each pattern consists of the sequence of <Entry>...</Entry> elements. Type member declarations are distributed between entries 343 | I.3 If pattern has RemoveAllRegions="true" attribute, then all regions will be cleared prior to reordering. Otherwise, only auto-generated regions will be cleared 344 | I.4 The contents of each entry is sorted by given keys (First key is primary, next key is secondary, etc). Then the declarations are grouped and en-regioned by given property 345 | 346 | II. Available match operands 347 | 348 | Each operand may have Weight="..." attribute. This weight will be added to the match weight if the operand is evaluated to 'true'. 349 | The default weight is 1 350 | 351 | II.1 Boolean functions: 352 | II.1.1 <And>....</And> 353 | II.1.2 <Or>....</Or> 354 | II.1.3 <Not>....</Not> 355 | 356 | II.2 Operands 357 | II.2.1 <Kind Is="..."/>. Kinds are: class, struct, interface, enum, delegate, type, constructor, destructor, property, indexer, method, operator, field, constant, event, member 358 | II.2.2 <Name Is="..." [IgnoreCase="true/false"] />. The 'Is' attribute contains regular expression 359 | II.2.3 <HasAttribute CLRName="..." [Inherit="true/false"] />. The 'CLRName' attribute contains regular expression 360 | II.2.4 <Access Is="..."/>. The 'Is' values are: public, protected, internal, protected internal, private 361 | II.2.5 <Static/> 362 | II.2.6 <Abstract/> 363 | II.2.7 <Virtual/> 364 | II.2.8 <Override/> 365 | II.2.9 <Sealed/> 366 | II.2.10 <Readonly/> 367 | II.2.11 <ImplementsInterface CLRName="..."/>. The 'CLRName' attribute contains regular expression 368 | II.2.12 <HandlesEvent /> 369 | --> 370 | 371 | <Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns"> 372 | <!-- http://www.thebooleanfrog.com/post/2011/11/24/ReSharper-StyleCop-and-MSpec-All-Together-Now.aspx --> 373 | <!-- Do not reorder COM interfaces --> 374 | <Pattern> 375 | <Match> 376 | <And Weight="2000"> 377 | <Kind Is="interface"/> 378 | <Or> 379 | <HasAttribute CLRName="System.Runtime.InteropServices.InterfaceTypeAttribute"/> 380 | <HasAttribute CLRName="System.Runtime.InteropServices.ComImport"/> 381 | </Or> 382 | </And> 383 | </Match> 384 | </Pattern> 385 | <!-- Do not reorder P/Invoke structs --> 386 | <Pattern> 387 | <Match> 388 | <And Weight="2000"> 389 | <Or> 390 | <Kind Is="struct"/> 391 | <Kind Is="class"/> 392 | </Or> 393 | <HasAttribute CLRName="System.Runtime.InteropServices.StructLayoutAttribute"/> 394 | </And> 395 | </Match> 396 | </Pattern> 397 | <!-- Do not reorder P/Invoke classes (called xxxNativeMethods) --> 398 | <Pattern> 399 | <Match> 400 | <And Weight="2000"> 401 | <Kind Is="class"/> 402 | <Name Is=".*NativeMethods" /> 403 | </And> 404 | </Match> 405 | </Pattern> 406 | <!-- StyleCop pattern --> 407 | <Pattern RemoveAllRegions="true"> 408 | <Match> 409 | <Or Weight="1000" > 410 | <Kind Is="class" /> 411 | <Kind Is="struct" /> 412 | <Kind Is="interface"/> 413 | </Or> 414 | </Match> 415 | <!-- constants and fields --> 416 | <Entry> 417 | <Match> 418 | <Or> 419 | <Kind Is="constant"/> 420 | <Kind Is="field"/> 421 | </Or> 422 | </Match> 423 | <Sort> 424 | <Access Order="public internal protected-internal protected private"/> 425 | <Kind Order="constant field"/> 426 | <Readonly/> 427 | <Static/> 428 | <Name/> 429 | </Sort> 430 | <!--<Group Region="Constants and Fields"/>--> 431 | </Entry> 432 | <!-- constructors and destructors --> 433 | <Entry> 434 | <Match> 435 | <Or Weight="200"> 436 | <Kind Is="constructor"/> 437 | <Kind Is="destructor"/> 438 | </Or> 439 | </Match> 440 | <Sort> 441 | <Static/> 442 | <Kind Order="constructor destructor"/> 443 | <Access Order="public internal protected-internal protected private"/> 444 | </Sort> 445 | <!--<Group Region="Constructors and Destructors"/>--> 446 | </Entry> 447 | <!-- delegates --> 448 | <Entry> 449 | <Match> 450 | <Kind Is="delegate"/> 451 | </Match> 452 | <Sort> 453 | <Access Order="public internal protected-internal protected private" /> 454 | <Static /> 455 | <Name/> 456 | </Sort> 457 | <!--<Group Region="Delegates"/>--> 458 | </Entry> 459 | <!-- public events --> 460 | <Entry> 461 | <Match> 462 | <And> 463 | <Kind Is="event"/> 464 | <Access Is="public"/> 465 | </And> 466 | </Match> 467 | <Sort> 468 | <Access Order="public" /> 469 | <Static /> 470 | <Name/> 471 | </Sort> 472 | <!--<Group Region="Public Events"/>--> 473 | </Entry> 474 | <!-- interface events --> 475 | <Entry> 476 | <Match> 477 | <And> 478 | <Kind Is="event"/> 479 | <ImplementsInterface/> 480 | </And> 481 | </Match> 482 | <Sort> 483 | <ImplementsInterface Immediate="true"/> 484 | <Name/> 485 | </Sort> 486 | <!--<Group Region="Explicit Interface Events" />--> 487 | </Entry> 488 | <!-- other events --> 489 | <Entry> 490 | <Match> 491 | <Kind Is="event"/> 492 | </Match> 493 | <Sort> 494 | <Access Order="public internal protected-internal protected private" /> 495 | <Static /> 496 | <Name/> 497 | </Sort> 498 | <!--<Group Region="Events"/>--></Entry> 499 | <!-- enum --> 500 | <Entry> 501 | <Match> 502 | <Kind Is="enum"/> 503 | </Match> 504 | <Sort> 505 | <Access Order="public internal protected-internal protected private" /> 506 | <Name/> 507 | </Sort> 508 | <!--<Group Region="Enums"/>--> 509 | </Entry> 510 | <!-- interfaces --> 511 | <Entry> 512 | <Match> 513 | <Kind Is="interface" /> 514 | </Match> 515 | <Sort> 516 | <Access Order="public internal protected-internal protected private" /> 517 | <Name/> 518 | </Sort> 519 | <!--<Group Region="Interfaces"/>--> 520 | </Entry> 521 | <!-- public properties --> 522 | <Entry> 523 | <Match> 524 | <And> 525 | <Kind Is="property"/> 526 | <Access Is="public"/> 527 | </And> 528 | </Match> 529 | <Sort> 530 | <Access Order="public"/> 531 | <Static/> 532 | <Name/> 533 | </Sort> 534 | <!--<Group Region="Public Properties"/>--> 535 | </Entry> 536 | <!-- interface properties --> 537 | <Entry> 538 | <Match> 539 | <And> 540 | <Kind Is="property"/> 541 | <ImplementsInterface/> 542 | </And> 543 | </Match> 544 | <Sort> 545 | <ImplementsInterface Immediate="true"/> 546 | <Name/> 547 | </Sort> 548 | <!--<Group Region="Explicit Interface Properties" />--> 549 | </Entry> 550 | <!-- other properties --> 551 | <Entry> 552 | <Match> 553 | <Kind Is="property"/> 554 | </Match> 555 | <Sort> 556 | <Access Order="public internal protected-internal protected private"/> 557 | <Static/> 558 | <Name/> 559 | </Sort> 560 | <!--<Group Region="Properties"/>--> 561 | </Entry> 562 | <!-- public indexers --> 563 | <Entry> 564 | <Match> 565 | <And> 566 | <Kind Is="indexer" Weight="1000" /> 567 | <Access Is="public"/> 568 | </And> 569 | </Match> 570 | <Sort> 571 | <Access Order="public" /> 572 | <Static/> 573 | <Name/> 574 | </Sort> 575 | <!--<Group Region="Public Indexers"/>--> 576 | </Entry> 577 | <!-- interface indexers --> 578 | <Entry> 579 | <Match> 580 | <And> 581 | <Kind Is="indexer" Weight="1000"/> 582 | <ImplementsInterface/> 583 | </And> 584 | </Match> 585 | <Sort> 586 | <ImplementsInterface Immediate="true"/> 587 | <Name/> 588 | </Sort> 589 | <!--<Group Region="Explicit Interface Indexers" />--> 590 | </Entry> 591 | <!-- other indexers --> 592 | <Entry> 593 | <Match> 594 | <Kind Is="indexer" Weight="1000" /> 595 | </Match> 596 | <Sort> 597 | <Access Order="public internal protected-internal protected private" /> 598 | <Static/> 599 | <Name/> 600 | </Sort> 601 | <!--<Group Region="Indexers"/>--> 602 | </Entry> 603 | <!-- public methods --> 604 | <Entry> 605 | <Match> 606 | <And> 607 | <Kind Is="method"/> 608 | <Access Is="public"/> 609 | </And> 610 | </Match> 611 | <Sort> 612 | <Access Order="public"/> 613 | <Static/> 614 | <Name/> 615 | </Sort> 616 | <!--<Group Region="Public Methods"/>--> 617 | </Entry> 618 | <!-- interface methods --> 619 | <Entry> 620 | <Match> 621 | <And> 622 | <Kind Is="method"/> 623 | <ImplementsInterface/> 624 | </And> 625 | </Match> 626 | <Sort> 627 | <ImplementsInterface Immediate="true"/> 628 | <Name/> 629 | </Sort> 630 | <!--<Group Region="Explicit Interface Methods" />--> 631 | </Entry> 632 | <!-- other methods --> 633 | <Entry> 634 | <Match> 635 | <Kind Is="method"/> 636 | </Match> 637 | <Sort> 638 | <Access Order="public internal protected-internal protected private"/> 639 | <Static/> 640 | <Name/> 641 | </Sort> 642 | <!--<Group Region="Methods"/>--> 643 | </Entry> 644 | <!-- operators --> 645 | <Entry> 646 | <Match> 647 | <Kind Is="operator"/> 648 | </Match> 649 | <Sort> 650 | <Access Order="public internal protected-internal protected private" /> 651 | <Static/> 652 | <Name/> 653 | </Sort> 654 | <!--<Group Region="Operators"/>--> 655 | </Entry> 656 | <!-- Nested structs --> 657 | <Entry> 658 | <Match> 659 | <Kind Is="struct" Weight="600" /> 660 | </Match> 661 | <Sort> 662 | <Static /> 663 | <Access Order="public internal protected-internal protected private" /> 664 | <Name/> 665 | </Sort> 666 | </Entry> 667 | <!-- Nested classes --> 668 | <Entry> 669 | <Match> 670 | <Kind Is="class" Weight="700" /> 671 | </Match> 672 | <Sort> 673 | <Static /> 674 | <Access Order="public internal protected-internal protected private" /> 675 | <Name/> 676 | </Sort> 677 | </Entry> 678 | <!-- all other members --> 679 | <Entry/> 680 | </Pattern> 681 | <!-- MSpec pattern --> 682 | <Pattern RemoveAllRegions="true"> 683 | <Match> 684 | <And Weight="100"> 685 | <Kind Is="class"/> 686 | <Or> 687 | <HasAttribute CLRName="Machine.Specifications.SubjectAttribute" Inherit="true"/> 688 | <Name Is="^when_.+" IgnoreCase="true" /> 689 | </Or> 690 | </And> 691 | </Match> 692 | <Entry> 693 | <Match> 694 | <And> 695 | <Kind Is="field"/> 696 | <Or> 697 | <Access Is="protected"/> 698 | <Static/> 699 | </Or> 700 | </And> 701 | </Match> 702 | </Entry> 703 | <Entry> 704 | <Match> 705 | <And> 706 | <Kind Is="field"/> 707 | <Name Is="^context(_once)?$" IgnoreCase="true"/> 708 | </And> 709 | </Match> 710 | </Entry> 711 | <Entry> 712 | <Match> 713 | <And> 714 | <Kind Is="field"/> 715 | <Name Is="^of$" IgnoreCase="true"/> 716 | </And> 717 | </Match> 718 | </Entry> 719 | <Entry> 720 | <Match> 721 | <And> 722 | <Kind Is="field"/> 723 | <Name Is="^after(_all)?$" IgnoreCase="true"/> 724 | </And> 725 | </Match> 726 | </Entry> 727 | <Entry> 728 | <Match> 729 | <And> 730 | <Kind Is="field"/> 731 | <Name Is="^should_.*$" IgnoreCase="true"/> 732 | </And> 733 | </Match> 734 | </Entry> 735 | <Entry> 736 | <Match> 737 | <And> 738 | <Kind Is="field"/> 739 | <Not> 740 | <Static/> 741 | </Not> 742 | </And> 743 | </Match> 744 | </Entry> 745 | <!-- All other members --> 746 | <Entry/> 747 | </Pattern> 748 | 749 | </Patterns> 750 | 751 | CustomLayout 752 | True 753 | True 754 | <data><IncludeFilters /><ExcludeFilters /></data> 755 | <data /> 756 | --------------------------------------------------------------------------------