├── BUILDING.md ├── TimeoutRetryAttributeExample ├── packages.config ├── TimeoutRetryAttributeExample.sln ├── AssemblyInfo.cs ├── TimeoutRetryAttribute.cs ├── TimeoutRetryAttributeTests.cs └── TimeoutRetryAttributeExample.csproj ├── nuget.config ├── DataDrivenTests ├── GenericTestFixture.cs ├── DataDrivenTestFixture.cs └── DataDrivenTests.csproj ├── README.md ├── money ├── Money.csproj ├── IMoney.cs ├── AssemblyInfo.cs ├── Money.cs ├── MoneyBag.cs └── MoneyTest.cs ├── syntax ├── AssertSyntax.csproj ├── AssemblyInfo.cs └── AssertSyntaxTests.cs ├── ExpectedExceptionExample ├── ExpectedExceptionTests.cs ├── ExpectedExceptionExample.csproj ├── ExpectedExceptionExample.sln └── ExpectedExceptionAttribute.cs ├── .github └── workflows │ └── CI.yml ├── LICENSE.txt └── Samples.sln /BUILDING.md: -------------------------------------------------------------------------------- 1 | ## Build 2 | 3 | The solution can be built and run using Visual Studio, Visual Studio Code, or the command line using `dotnet test`. 4 | 5 | There is a CI build on github actions that runs on every push and pullrequest to any branch. 6 | -------------------------------------------------------------------------------- /TimeoutRetryAttributeExample/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DataDrivenTests/GenericTestFixture.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace DataDrivenTests 4 | { 5 | [TestFixture(typeof(int))] 6 | [TestFixture(typeof(string))] 7 | public class GenericTestFixture 8 | { 9 | [Test] 10 | public void TestType() 11 | { 12 | Assert.Pass($"The generic test type is {typeof(T)}"); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DataDrivenTests/DataDrivenTestFixture.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace DataDrivenTests 4 | { 5 | [TestFixture(10)] 6 | [TestFixture(42)] 7 | public class DataDrivenTestFixture 8 | { 9 | int _x; 10 | 11 | public DataDrivenTestFixture(int x) 12 | { 13 | _x = x; 14 | } 15 | 16 | [Test] 17 | public void TestArguments() 18 | { 19 | Assert.Pass($"X is {_x}"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nunit-samples-csharp 2 | ==================== 3 | 4 | Samples of NUnit Usage in C# 5 | * **money** Implementation and tests of a currency conversion class 6 | * **syntax** Examples of NUnit syntax in C# 7 | * **ExpectedExceptionExample** Shows how to implement a custom attribute for NUnit 8 | * **TimeoutRetryAttributeExample** Shows how to implement a custom retry attribute for NUnit that will be triggered only in case of timeout (useful with flaky tests due to poor network connection) 9 | -------------------------------------------------------------------------------- /money/Money.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | Copyright ©NUnit 2018 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /syntax/AssertSyntax.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | Copyright ©NUnit 2018 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /DataDrivenTests/DataDrivenTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | Copyright ©NUnit 2018 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ExpectedExceptionExample/ExpectedExceptionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace ExpectedExceptionExample 5 | { 6 | [TestFixture] 7 | public class ExpectedExceptionTests 8 | { 9 | [Test] 10 | [ExpectedException(typeof(ArgumentException))] 11 | public void HandlesArgumentExceptionAsType() 12 | { 13 | throw new ArgumentException(); 14 | } 15 | 16 | [Test] 17 | public void HandlesArgumentExceptionWithNewSyntax() 18 | { 19 | Assert.Throws(() => throw new ArgumentException()); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ExpectedExceptionExample/ExpectedExceptionExample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | Copyright ©NUnit 2018 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: .NET 5 | 6 | on: [push, pull_request] 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Setup .NET 16 | uses: actions/setup-dotnet@v3 17 | with: 18 | dotnet-version: 6.0.x 19 | - name: Restore dependencies 20 | run: dotnet restore 21 | - name: Build 22 | run: dotnet build --no-restore 23 | - name: Test 24 | run: dotnet test --no-build --verbosity normal 25 | -------------------------------------------------------------------------------- /money/IMoney.cs: -------------------------------------------------------------------------------- 1 | namespace Money 2 | { 3 | 4 | /// The common interface for simple Monies and MoneyBags. 5 | interface IMoney 6 | { 7 | /// Adds a money to this money. 8 | IMoney Add(IMoney m); 9 | 10 | /// Adds a simple Money to this money. This is a helper method for 11 | /// implementing double dispatch. 12 | IMoney AddMoney(Money m); 13 | 14 | /// Adds a MoneyBag to this money. This is a helper method for 15 | /// implementing double dispatch. 16 | IMoney AddMoneyBag(MoneyBag s); 17 | 18 | /// True if this money is zero. 19 | bool IsZero { get; } 20 | 21 | /// Multiplies a money by the given factor. 22 | IMoney Multiply(int factor); 23 | 24 | /// Negates this money. 25 | IMoney Negate(); 26 | 27 | /// Subtracts a money from this money. 28 | IMoney Subtract(IMoney m); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ExpectedExceptionExample/ExpectedExceptionExample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpectedExceptionExample", "ExpectedExceptionExample.csproj", "{A6E1D464-9AAF-4CA9-A818-819739132281}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {A6E1D464-9AAF-4CA9-A818-819739132281}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {A6E1D464-9AAF-4CA9-A818-819739132281}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {A6E1D464-9AAF-4CA9-A818-819739132281}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {A6E1D464-9AAF-4CA9-A818-819739132281}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Rob Prouse, Charlie Poole 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /TimeoutRetryAttributeExample/TimeoutRetryAttributeExample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.572 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimeoutRetryAttributeExample", "TimeoutRetryAttributeExample.csproj", "{C9A7C840-8C27-4964-9BCE-9B05F5662199}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C9A7C840-8C27-4964-9BCE-9B05F5662199}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {C9A7C840-8C27-4964-9BCE-9B05F5662199}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {C9A7C840-8C27-4964-9BCE-9B05F5662199}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {C9A7C840-8C27-4964-9BCE-9B05F5662199}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {6917CCEF-6B80-445A-9968-6652195E26AD} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /TimeoutRetryAttributeExample/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TimeoutRetryAttributeExample")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TimeoutRetryAttributeExample")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c9a7c840-8c27-4964-9bce-9b05f5662199")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /money/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // 5 | // In order to sign your assembly you must specify a key to use. Refer to the 6 | // Microsoft .NET Framework documentation for more information on assembly signing. 7 | // 8 | // Use the attributes below to control which key is used for signing. 9 | // 10 | // Notes: 11 | // (*) If no key is specified, the assembly is not signed. 12 | // (*) KeyName refers to a key that has been installed in the Crypto Service 13 | // Provider (CSP) on your machine. KeyFile refers to a file which contains 14 | // a key. 15 | // (*) If the KeyFile and the KeyName values are both specified, the 16 | // following processing occurs: 17 | // (1) If the KeyName can be found in the CSP, that key is used. 18 | // (2) If the KeyName does not exist and the KeyFile does exist, the key 19 | // in the KeyFile is installed into the CSP and used. 20 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. 21 | // When specifying the KeyFile, the location of the KeyFile should be 22 | // relative to the project output directory which is 23 | // %Project Directory%\obj\. For example, if your KeyFile is 24 | // located in the project directory, you would specify the AssemblyKeyFile 25 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 26 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework 27 | // documentation for more information on this. 28 | // 29 | [assembly: AssemblyDelaySign(false)] 30 | [assembly: AssemblyKeyFile("")] 31 | [assembly: AssemblyKeyName("")] 32 | -------------------------------------------------------------------------------- /syntax/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // 5 | // In order to sign your assembly you must specify a key to use. Refer to the 6 | // Microsoft .NET Framework documentation for more information on assembly signing. 7 | // 8 | // Use the attributes below to control which key is used for signing. 9 | // 10 | // Notes: 11 | // (*) If no key is specified, the assembly is not signed. 12 | // (*) KeyName refers to a key that has been installed in the Crypto Service 13 | // Provider (CSP) on your machine. KeyFile refers to a file which contains 14 | // a key. 15 | // (*) If the KeyFile and the KeyName values are both specified, the 16 | // following processing occurs: 17 | // (1) If the KeyName can be found in the CSP, that key is used. 18 | // (2) If the KeyName does not exist and the KeyFile does exist, the key 19 | // in the KeyFile is installed into the CSP and used. 20 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. 21 | // When specifying the KeyFile, the location of the KeyFile should be 22 | // relative to the project output directory which is 23 | // %Project Directory%\obj\. For example, if your KeyFile is 24 | // located in the project directory, you would specify the AssemblyKeyFile 25 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] 26 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework 27 | // documentation for more information on this. 28 | // 29 | [assembly: AssemblyDelaySign(false)] 30 | [assembly: AssemblyKeyFile("")] 31 | [assembly: AssemblyKeyName("")] 32 | -------------------------------------------------------------------------------- /ExpectedExceptionExample/ExpectedExceptionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using NUnit.Framework.Interfaces; 4 | using NUnit.Framework.Internal; 5 | using NUnit.Framework.Internal.Commands; 6 | 7 | namespace ExpectedExceptionExample 8 | { 9 | /// 10 | /// A simple ExpectedExceptionAttribute 11 | /// 12 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 13 | public class ExpectedExceptionAttribute : NUnitAttribute, IWrapTestMethod 14 | { 15 | private readonly Type _expectedExceptionType; 16 | 17 | public ExpectedExceptionAttribute(Type type) 18 | { 19 | _expectedExceptionType = type; 20 | } 21 | 22 | public TestCommand Wrap(TestCommand command) 23 | { 24 | return new ExpectedExceptionCommand(command, _expectedExceptionType); 25 | } 26 | 27 | private class ExpectedExceptionCommand : DelegatingTestCommand 28 | { 29 | private readonly Type _expectedType; 30 | 31 | public ExpectedExceptionCommand(TestCommand innerCommand, Type expectedType) 32 | : base(innerCommand) 33 | { 34 | _expectedType = expectedType; 35 | } 36 | 37 | public override TestResult Execute(TestExecutionContext context) 38 | { 39 | Type caughtType = null; 40 | 41 | try 42 | { 43 | innerCommand.Execute(context); 44 | } 45 | catch (Exception ex) 46 | { 47 | if (ex is NUnitException) 48 | ex = ex.InnerException; 49 | caughtType = ex.GetType(); 50 | } 51 | 52 | if (caughtType == _expectedType) 53 | context.CurrentResult.SetResult(ResultState.Success); 54 | else if (caughtType != null) 55 | context.CurrentResult.SetResult(ResultState.Failure, 56 | $"Expected {_expectedType.Name} but got {caughtType.Name}"); 57 | else 58 | context.CurrentResult.SetResult(ResultState.Failure, 59 | $"Expected {_expectedType.Name} but no exception was thrown"); 60 | 61 | return context.CurrentResult; 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /money/Money.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Money 5 | { 6 | /// A simple Money. 7 | class Money : IMoney 8 | { 9 | 10 | private int fAmount; 11 | private String fCurrency; 12 | 13 | /// Constructs a money from the given amount and 14 | /// currency. 15 | public Money(int amount, String currency) 16 | { 17 | fAmount = amount; 18 | fCurrency = currency; 19 | } 20 | 21 | /// Adds a money to this money. Forwards the request to 22 | /// the AddMoney helper. 23 | public IMoney Add(IMoney m) 24 | { 25 | return m.AddMoney(this); 26 | } 27 | 28 | public IMoney AddMoney(Money m) 29 | { 30 | if (m.Currency.Equals(Currency)) 31 | return new Money(Amount + m.Amount, Currency); 32 | return new MoneyBag(this, m); 33 | } 34 | 35 | public IMoney AddMoneyBag(MoneyBag s) 36 | { 37 | return s.AddMoney(this); 38 | } 39 | 40 | public int Amount 41 | { 42 | get { return fAmount; } 43 | } 44 | 45 | public String Currency 46 | { 47 | get { return fCurrency; } 48 | } 49 | 50 | public override bool Equals(Object anObject) 51 | { 52 | if (IsZero) 53 | if (anObject is IMoney) 54 | return ((IMoney)anObject).IsZero; 55 | if (anObject is Money) 56 | { 57 | Money aMoney = (Money)anObject; 58 | return aMoney.Currency.Equals(Currency) 59 | && Amount == aMoney.Amount; 60 | } 61 | return false; 62 | } 63 | 64 | public override int GetHashCode() 65 | { 66 | return fCurrency.GetHashCode() + fAmount; 67 | } 68 | 69 | public bool IsZero 70 | { 71 | get { return Amount == 0; } 72 | } 73 | 74 | public IMoney Multiply(int factor) 75 | { 76 | return new Money(Amount * factor, Currency); 77 | } 78 | 79 | public IMoney Negate() 80 | { 81 | return new Money(-Amount, Currency); 82 | } 83 | 84 | public IMoney Subtract(IMoney m) 85 | { 86 | return Add(m.Negate()); 87 | } 88 | 89 | public override String ToString() 90 | { 91 | StringBuilder buffer = new StringBuilder(); 92 | buffer.Append("[" + Amount + " " + Currency + "]"); 93 | return buffer.ToString(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Samples.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33627.172 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Money", "money\Money.csproj", "{11EDF872-A04D-4F75-A1BF-71168DC86AF3}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExpectedExceptionExample", "ExpectedExceptionExample\ExpectedExceptionExample.csproj", "{A6E1D464-9AAF-4CA9-A818-819739132281}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssertSyntax", "syntax\AssertSyntax.csproj", "{06F46FA2-687B-4B46-A912-C1B0B4CC1B20}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{51996B31-851B-463C-8B57-A7E51CA034EC}" 13 | ProjectSection(SolutionItems) = preProject 14 | .gitattributes = .gitattributes 15 | .gitignore = .gitignore 16 | BUILDING.md = BUILDING.md 17 | LICENSE.txt = LICENSE.txt 18 | nuget.config = nuget.config 19 | README.md = README.md 20 | EndProjectSection 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataDrivenTests", "DataDrivenTests\DataDrivenTests.csproj", "{FBBC6F15-E718-4080-832C-9D1F4B7A352A}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {11EDF872-A04D-4F75-A1BF-71168DC86AF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {11EDF872-A04D-4F75-A1BF-71168DC86AF3}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {11EDF872-A04D-4F75-A1BF-71168DC86AF3}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {11EDF872-A04D-4F75-A1BF-71168DC86AF3}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {A6E1D464-9AAF-4CA9-A818-819739132281}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {A6E1D464-9AAF-4CA9-A818-819739132281}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {A6E1D464-9AAF-4CA9-A818-819739132281}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {A6E1D464-9AAF-4CA9-A818-819739132281}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {06F46FA2-687B-4B46-A912-C1B0B4CC1B20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {06F46FA2-687B-4B46-A912-C1B0B4CC1B20}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {06F46FA2-687B-4B46-A912-C1B0B4CC1B20}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {06F46FA2-687B-4B46-A912-C1B0B4CC1B20}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {FBBC6F15-E718-4080-832C-9D1F4B7A352A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {FBBC6F15-E718-4080-832C-9D1F4B7A352A}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {FBBC6F15-E718-4080-832C-9D1F4B7A352A}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {FBBC6F15-E718-4080-832C-9D1F4B7A352A}.Release|Any CPU.Build.0 = Release|Any CPU 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | GlobalSection(ExtensibilityGlobals) = postSolution 51 | SolutionGuid = {381F12E7-0FE3-4A81-8427-2BA14C454821} 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /TimeoutRetryAttributeExample/TimeoutRetryAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Text.RegularExpressions; 4 | using NUnit.Framework; 5 | using NUnit.Framework.Interfaces; 6 | using NUnit.Framework.Internal; 7 | using NUnit.Framework.Internal.Commands; 8 | 9 | namespace TimeoutRetryAttributeExample 10 | { 11 | /// 12 | /// Specifies that a test method should be rerun on timeout set by MaxTime attribute up to the specified 13 | /// maximum number of times. Failure will be reported on assertion fail or exception 14 | /// 15 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 16 | public class TimeoutRetryAttribute : PropertyAttribute, IWrapSetUpTearDown 17 | { 18 | private int _tryCount; 19 | 20 | public TimeoutRetryAttribute(int tryCount) : base(tryCount) 21 | { 22 | _tryCount = tryCount; 23 | } 24 | 25 | #region IWrapSetUpTearDown Members 26 | 27 | public TestCommand Wrap(TestCommand command) 28 | { 29 | return new RetryCommand(command, _tryCount); 30 | } 31 | 32 | #endregion 33 | 34 | #region Nested RetryCommand Class 35 | 36 | public class RetryCommand : DelegatingTestCommand 37 | { 38 | private int _tryCount; 39 | 40 | public RetryCommand(TestCommand innerCommand, int tryCount) 41 | : base(innerCommand) 42 | { 43 | _tryCount = tryCount; 44 | } 45 | 46 | public override TestResult Execute(TestExecutionContext context) 47 | { 48 | // Check for attribute dependencies at [Test] level or parent when [TestCase]/[TestCaseSource] is used to generate test cases 49 | if (!context.CurrentTest.Properties.Keys.Contains(PropertyNames.MaxTime) && !context.CurrentTest.Parent.Properties.Keys.Contains(PropertyNames.MaxTime)) 50 | { 51 | throw new NullReferenceException($"{PropertyNames.MaxTime} attribute must be set along with TimeoutRetry"); 52 | } 53 | 54 | int count = _tryCount; 55 | 56 | while (count-- > 0) 57 | { 58 | context.CurrentResult = innerCommand.Execute(context); 59 | 60 | // Skip retry only with passed assertions or if failure is different than timeout 61 | if (context.CurrentResult.ResultState != ResultState.Failure || !Regex.IsMatch(context.CurrentResult.Message, "Elapsed time of [0-9.,]*ms exceeds maximum of [0-9]*ms")) // NUnit.Framework.Internal.Commands.MaxTimeCommand 62 | break; 63 | 64 | // Clear result for retry 65 | if (count > 0) 66 | { 67 | context.CurrentResult = context.CurrentTest.MakeTestResult(); 68 | context.StartTicks = Stopwatch.GetTimestamp(); // Reset test execution start time, so that only last run is included in 'Elapsed time' 69 | } 70 | 71 | } 72 | 73 | return context.CurrentResult; 74 | } 75 | } 76 | 77 | #endregion 78 | } 79 | } -------------------------------------------------------------------------------- /TimeoutRetryAttributeExample/TimeoutRetryAttributeTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | 6 | namespace TimeoutRetryAttributeExample 7 | { 8 | [TestFixture] 9 | public class TimeoutRetryAttributeTests 10 | { 11 | // Retry counters for corresponding test methods 12 | readonly Dictionary retryCount = new Dictionary() 13 | { 14 | { "RetryIsFiredDueToTimeout", 0 }, 15 | { "RetryIsNotFiredDueToTimeout", 0 }, 16 | { "RetryIsNotFiredDueToFailedAssertion", 0 }, 17 | { "RetryIsNotFiredDueToException", 0 }, 18 | { "RetryIsFiredDueToTimeoutAndLimitNotReached", 0 } 19 | }; 20 | 21 | // This test should execute 3 times and fail due to reached retry number limit 22 | [Test] 23 | [MaxTime(1000)] 24 | [TimeoutRetry(3)] 25 | public void RetryIsFiredDueToTimeout() 26 | { 27 | TestContext.Out.WriteLine($"Running test for the {++retryCount["RetryIsFiredDueToTimeout"]} time"); 28 | Thread.Sleep(3000); // Wait more than MaxTime threshold 29 | } 30 | 31 | // This test should not retry at all and pass within first execution 32 | [Test] 33 | [MaxTime(3000)] 34 | [TimeoutRetry(5)] 35 | public void RetryIsNotFiredDueToLackOfTimeout() 36 | { 37 | TestContext.Out.WriteLine($"Running test for the {++retryCount["RetryIsNotFiredDueToTimeout"]} time"); 38 | Thread.Sleep(1000); // Wait less than MaxTime threshold 39 | } 40 | 41 | // This test should not retry due to failed assertion despite having reached the MaxTime threshold 42 | [Test] 43 | [MaxTime(1000)] 44 | [TimeoutRetry(10)] 45 | public void RetryIsNotFiredDueToFailedAssertion() 46 | { 47 | TestContext.Out.WriteLine($"Running test for the {++retryCount["RetryIsNotFiredDueToFailedAssertion"]} time"); 48 | Thread.Sleep(3000); // Wait more than MaxTime threshold 49 | Assert.Fail("I failed"); // Introduce assertion failure 50 | } 51 | 52 | // This test should not retry due to thrown exception despite having reached the MaxTime threshold 53 | [Test] 54 | [MaxTime(1000)] 55 | [TimeoutRetry(2)] 56 | public void RetryIsNotFiredDueToException() 57 | { 58 | TestContext.Out.WriteLine($"Running test for the {++retryCount["RetryIsNotFiredDueToException"]} time"); 59 | Thread.Sleep(3000); // Wait more than MaxTime threshold 60 | throw new Exception("Exception thrown"); // Throw exception 61 | } 62 | 63 | // This test should execute 3 times and fail 2 times due to reached retry number limit, then pass on the 3 run 64 | [Test] 65 | [MaxTime(2000)] 66 | [TimeoutRetry(3)] 67 | public void RetryIsFiredDueToTimeoutAndLimitNotReached() 68 | { 69 | TestContext.Out.WriteLine($"Running test for the {++retryCount["RetryIsFiredDueToTimeoutAndLimitNotReached"]} time"); 70 | TestContext.Out.WriteLine(retryCount["RetryIsFiredDueToTimeoutAndLimitNotReached"]); 71 | if (retryCount["RetryIsFiredDueToTimeoutAndLimitNotReached"] < 3) // For 1 & 2 retry force timeout 72 | { 73 | Thread.Sleep(3000); // Wait more than MaxTime threshold 74 | } 75 | else 76 | { 77 | Thread.Sleep(1000); // Wait less than MaxTime threshold 78 | } 79 | Assert.True(true); // Add valid assertion 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /TimeoutRetryAttributeExample/TimeoutRetryAttributeExample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Debug 8 | AnyCPU 9 | {C9A7C840-8C27-4964-9BCE-9B05F5662199} 10 | Library 11 | Properties 12 | TimeoutRetryAttributeExample 13 | TimeoutRetryAttributeExample 14 | v4.6.1 15 | 512 16 | true 17 | 18 | 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | packages\NUnit.3.12.0\lib\net45\nunit.framework.dll 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /money/MoneyBag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Text; 4 | 5 | namespace Money 6 | { 7 | /// A MoneyBag defers exchange rate conversions. 8 | /// For example adding 9 | /// 12 Swiss Francs to 14 US Dollars is represented as a bag 10 | /// containing the two Monies 12 CHF and 14 USD. Adding another 11 | /// 10 Swiss francs gives a bag with 22 CHF and 14 USD. Due to 12 | /// the deferred exchange rate conversion we can later value a 13 | /// MoneyBag with different exchange rates. 14 | /// 15 | /// A MoneyBag is represented as a list of Monies and provides 16 | /// different constructors to create a MoneyBag. 17 | class MoneyBag : IMoney 18 | { 19 | private ArrayList fMonies = new ArrayList(5); 20 | 21 | private MoneyBag() 22 | { 23 | } 24 | public MoneyBag(Money[] bag) 25 | { 26 | for (int i = 0; i < bag.Length; i++) 27 | { 28 | if (!bag[i].IsZero) 29 | AppendMoney(bag[i]); 30 | } 31 | } 32 | public MoneyBag(Money m1, Money m2) 33 | { 34 | AppendMoney(m1); 35 | AppendMoney(m2); 36 | } 37 | public MoneyBag(Money m, MoneyBag bag) 38 | { 39 | AppendMoney(m); 40 | AppendBag(bag); 41 | } 42 | public MoneyBag(MoneyBag m1, MoneyBag m2) 43 | { 44 | AppendBag(m1); 45 | AppendBag(m2); 46 | } 47 | public IMoney Add(IMoney m) 48 | { 49 | return m.AddMoneyBag(this); 50 | } 51 | public IMoney AddMoney(Money m) 52 | { 53 | return (new MoneyBag(m, this)).Simplify(); 54 | } 55 | public IMoney AddMoneyBag(MoneyBag s) 56 | { 57 | return (new MoneyBag(s, this)).Simplify(); 58 | } 59 | private void AppendBag(MoneyBag aBag) 60 | { 61 | foreach (Money m in aBag.fMonies) 62 | AppendMoney(m); 63 | } 64 | private void AppendMoney(Money aMoney) 65 | { 66 | IMoney old = FindMoney(aMoney.Currency); 67 | if (old == null) 68 | { 69 | fMonies.Add(aMoney); 70 | return; 71 | } 72 | fMonies.Remove(old); 73 | IMoney sum = old.Add(aMoney); 74 | if (sum.IsZero) 75 | return; 76 | fMonies.Add(sum); 77 | } 78 | private bool Contains(Money aMoney) 79 | { 80 | Money m = FindMoney(aMoney.Currency); 81 | return m.Amount == aMoney.Amount; 82 | } 83 | public override bool Equals(Object anObject) 84 | { 85 | if (IsZero) 86 | if (anObject is IMoney) 87 | return ((IMoney)anObject).IsZero; 88 | 89 | if (anObject is MoneyBag) 90 | { 91 | MoneyBag aMoneyBag = (MoneyBag)anObject; 92 | if (aMoneyBag.fMonies.Count != fMonies.Count) 93 | return false; 94 | 95 | foreach (Money m in fMonies) 96 | { 97 | if (!aMoneyBag.Contains(m)) 98 | return false; 99 | } 100 | return true; 101 | } 102 | return false; 103 | } 104 | private Money FindMoney(String currency) 105 | { 106 | foreach (Money m in fMonies) 107 | { 108 | if (m.Currency.Equals(currency)) 109 | return m; 110 | } 111 | return null; 112 | } 113 | public override int GetHashCode() 114 | { 115 | int hash = 0; 116 | foreach (Money m in fMonies) 117 | { 118 | hash ^= m.GetHashCode(); 119 | } 120 | return hash; 121 | } 122 | public bool IsZero 123 | { 124 | get { return fMonies.Count == 0; } 125 | } 126 | public IMoney Multiply(int factor) 127 | { 128 | MoneyBag result = new MoneyBag(); 129 | if (factor != 0) 130 | { 131 | foreach (Money m in fMonies) 132 | { 133 | result.AppendMoney((Money)m.Multiply(factor)); 134 | } 135 | } 136 | return result; 137 | } 138 | public IMoney Negate() 139 | { 140 | MoneyBag result = new MoneyBag(); 141 | foreach (Money m in fMonies) 142 | { 143 | result.AppendMoney((Money)m.Negate()); 144 | } 145 | return result; 146 | } 147 | private IMoney Simplify() 148 | { 149 | if (fMonies.Count == 1) 150 | return (IMoney)fMonies[0]; 151 | return this; 152 | } 153 | public IMoney Subtract(IMoney m) 154 | { 155 | return Add(m.Negate()); 156 | } 157 | public override String ToString() 158 | { 159 | StringBuilder buffer = new StringBuilder(); 160 | buffer.Append("{"); 161 | foreach (Money m in fMonies) 162 | buffer.Append(m); 163 | buffer.Append("}"); 164 | return buffer.ToString(); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /money/MoneyTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using NUnit.Framework.Legacy; 3 | 4 | namespace Money 5 | { 6 | /// 7 | /// Tests Money 8 | /// 9 | /// 10 | [TestFixture] 11 | public class MoneyTest 12 | { 13 | private Money f12CHF; 14 | private Money f14CHF; 15 | private Money f7USD; 16 | private Money f21USD; 17 | 18 | private MoneyBag fMB1; 19 | private MoneyBag fMB2; 20 | 21 | /// 22 | /// Initializes Money test objects 23 | /// 24 | /// 25 | [SetUp] 26 | protected void SetUp() 27 | { 28 | f12CHF = new Money(12, "CHF"); 29 | f14CHF = new Money(14, "CHF"); 30 | f7USD = new Money(7, "USD"); 31 | f21USD = new Money(21, "USD"); 32 | 33 | fMB1 = new MoneyBag(f12CHF, f7USD); 34 | fMB2 = new MoneyBag(f14CHF, f21USD); 35 | } 36 | 37 | /// 38 | /// Assert that Moneybags multiply correctly 39 | /// 40 | /// 41 | [Test] 42 | public void BagMultiply() 43 | { 44 | // {[12 CHF][7 USD]} *2 == {[24 CHF][14 USD]} 45 | Money[] bag = { new Money(24, "CHF"), new Money(14, "USD") }; 46 | var expected = new MoneyBag(bag); 47 | Assert.That(fMB1.Multiply(2), Is.EqualTo(expected)); 48 | Assert.That(fMB1.Multiply(1), Is.EqualTo(fMB1)); 49 | ClassicAssert.IsTrue(fMB1.Multiply(0).IsZero); 50 | } 51 | 52 | /// 53 | /// Assert that Moneybags negate(positive to negative values) correctly 54 | /// 55 | /// 56 | [Test] 57 | public void BagNegate() 58 | { 59 | // {[12 CHF][7 USD]} negate == {[-12 CHF][-7 USD]} 60 | Money[] bag = { new Money(-12, "CHF"), new Money(-7, "USD") }; 61 | var expected = new MoneyBag(bag); 62 | Assert.That(fMB1.Negate(), Is.EqualTo(expected)); 63 | } 64 | 65 | /// 66 | /// Assert that adding currency to Moneybags happens correctly 67 | /// 68 | /// 69 | [Test] 70 | public void BagSimpleAdd() 71 | { 72 | // {[12 CHF][7 USD]} + [14 CHF] == {[26 CHF][7 USD]} 73 | Money[] bag = { new Money(26, "CHF"), new Money(7, "USD") }; 74 | var expected = new MoneyBag(bag); 75 | Assert.That(fMB1.Add(f14CHF), Is.EqualTo(expected)); 76 | } 77 | 78 | /// 79 | /// Assert that subtracting currency to Moneybags happens correctly 80 | /// 81 | /// 82 | [Test] 83 | public void BagSubtract() 84 | { 85 | // {[12 CHF][7 USD]} - {[14 CHF][21 USD] == {[-2 CHF][-14 USD]} 86 | Money[] bag = { new Money(-2, "CHF"), new Money(-14, "USD") }; 87 | var expected = new MoneyBag(bag); 88 | Assert.That(fMB1.Subtract(fMB2), Is.EqualTo(expected)); 89 | } 90 | 91 | /// 92 | /// Assert that adding multiple currencies to Moneybags in one statement happens correctly 93 | /// 94 | /// 95 | [Test] 96 | public void BagSumAdd() 97 | { 98 | // {[12 CHF][7 USD]} + {[14 CHF][21 USD]} == {[26 CHF][28 USD]} 99 | Money[] bag = { new Money(26, "CHF"), new Money(28, "USD") }; 100 | var expected = new MoneyBag(bag); 101 | Assert.That(fMB1.Add(fMB2), Is.EqualTo(expected)); 102 | } 103 | 104 | /// 105 | /// Assert that Moneybags hold zero value after adding zero value 106 | /// 107 | /// 108 | [Test] 109 | public void IsZero() 110 | { 111 | ClassicAssert.IsTrue(fMB1.Subtract(fMB1).IsZero); 112 | 113 | Money[] bag = { new Money(0, "CHF"), new Money(0, "USD") }; 114 | ClassicAssert.IsTrue(new MoneyBag(bag).IsZero); 115 | } 116 | 117 | /// 118 | /// Assert that a new bag is the same as adding value to an existing bag 119 | /// 120 | /// 121 | [Test] 122 | public void MixedSimpleAdd() 123 | { 124 | // [12 CHF] + [7 USD] == {[12 CHF][7 USD]} 125 | Money[] bag = { f12CHF, f7USD }; 126 | var expected = new MoneyBag(bag); 127 | Assert.That(f12CHF.Add(f7USD), Is.EqualTo(expected)); 128 | } 129 | 130 | /// 131 | /// Assert that MoneyBag.Equals() works correctly 132 | /// 133 | /// 134 | [Test] 135 | public void MoneyBagEquals() 136 | { 137 | //NOTE: Normally we use Assert.AreEqual to test whether two 138 | // objects are equal. But here we are testing the MoneyBag.Equals() 139 | // method itself, so using AreEqual would not serve the purpose. 140 | ClassicAssert.IsFalse(fMB1.Equals(null)); 141 | 142 | ClassicAssert.IsTrue(fMB1.Equals(fMB1)); 143 | var equal = new MoneyBag(new Money(12, "CHF"), new Money(7, "USD")); 144 | ClassicAssert.IsTrue(fMB1.Equals(equal)); 145 | ClassicAssert.IsTrue(!fMB1.Equals(f12CHF)); 146 | ClassicAssert.IsTrue(!f12CHF.Equals(fMB1)); 147 | ClassicAssert.IsTrue(!fMB1.Equals(fMB2)); 148 | } 149 | 150 | /// 151 | /// Assert that the hash of a new bag is the same as 152 | /// the hash of an existing bag with added value 153 | /// 154 | /// 155 | [Test] 156 | public void MoneyBagHash() 157 | { 158 | var equal = new MoneyBag(new Money(12, "CHF"), new Money(7, "USD")); 159 | Assert.That(equal.GetHashCode(), Is.EqualTo(fMB1.GetHashCode())); 160 | } 161 | 162 | /// 163 | /// Assert that Money.Equals() works correctly 164 | /// 165 | /// 166 | [Test] 167 | public void MoneyEquals() 168 | { 169 | //NOTE: Normally we use Assert.AreEqual to test whether two 170 | // objects are equal. But here we are testing the MoneyBag.Equals() 171 | // method itself, so using AreEqual would not serve the purpose. 172 | ClassicAssert.IsFalse(f12CHF.Equals(null)); 173 | var equalMoney = new Money(12, "CHF"); 174 | ClassicAssert.IsTrue(f12CHF.Equals(f12CHF)); 175 | ClassicAssert.IsTrue(f12CHF.Equals(equalMoney)); 176 | ClassicAssert.IsFalse(f12CHF.Equals(f14CHF)); 177 | } 178 | 179 | /// 180 | /// Assert that the hash of new Money is the same as 181 | /// the hash of initialized Money 182 | /// 183 | /// 184 | [Test] 185 | public void MoneyHash() 186 | { 187 | ClassicAssert.IsFalse(f12CHF.Equals(null)); 188 | var equal = new Money(12, "CHF"); 189 | Assert.That(equal.GetHashCode(), Is.EqualTo(f12CHF.GetHashCode())); 190 | } 191 | 192 | /// 193 | /// Assert that adding multiple small values is the same as adding one big value 194 | /// 195 | /// 196 | [Test] 197 | public void Normalize() 198 | { 199 | Money[] bag = { new Money(26, "CHF"), new Money(28, "CHF"), new Money(6, "CHF") }; 200 | var moneyBag = new MoneyBag(bag); 201 | Money[] expected = { new Money(60, "CHF") }; 202 | // note: expected is still a MoneyBag 203 | var expectedBag = new MoneyBag(expected); 204 | Assert.That(moneyBag, Is.EqualTo(expectedBag)); 205 | } 206 | 207 | /// 208 | /// Assert that removing a value is the same as not having such a value 209 | /// 210 | /// 211 | [Test] 212 | public void Normalize2() 213 | { 214 | // {[12 CHF][7 USD]} - [12 CHF] == [7 USD] 215 | var expected = new Money(7, "USD"); 216 | Assert.That(fMB1.Subtract(f12CHF), Is.EqualTo(expected)); 217 | } 218 | 219 | /// 220 | /// Assert that removing multiple values works correctly 221 | /// 222 | /// 223 | [Test] 224 | public void Normalize3() 225 | { 226 | // {[12 CHF][7 USD]} - {[12 CHF][3 USD]} == [4 USD] 227 | Money[] s1 = { new Money(12, "CHF"), new Money(3, "USD") }; 228 | var ms1 = new MoneyBag(s1); 229 | var expected = new Money(4, "USD"); 230 | Assert.That(fMB1.Subtract(ms1), Is.EqualTo(expected)); 231 | } 232 | 233 | /// 234 | /// Assert that if value is subtracted from 0, the result will be negative. 235 | /// 236 | /// 237 | [Test] 238 | public void Normalize4() 239 | { 240 | // [12 CHF] - {[12 CHF][3 USD]} == [-3 USD] 241 | Money[] s1 = { new Money(12, "CHF"), new Money(3, "USD") }; 242 | var ms1 = new MoneyBag(s1); 243 | var expected = new Money(-3, "USD"); 244 | Assert.That(f12CHF.Subtract(ms1), Is.EqualTo(expected)); 245 | } 246 | 247 | /// 248 | /// Assert that Money.ToString() function works correctly 249 | /// 250 | /// 251 | [Test] 252 | public void Print() 253 | { 254 | Assert.That(f12CHF.ToString(), Is.EqualTo("[12 CHF]")); 255 | } 256 | 257 | /// 258 | /// Assert that adding more value to Money happens correctly 259 | /// 260 | /// 261 | [Test] 262 | public void SimpleAdd() 263 | { 264 | // [12 CHF] + [14 CHF] == [26 CHF] 265 | var expected = new Money(26, "CHF"); 266 | Assert.That(f12CHF.Add(f14CHF), Is.EqualTo(expected)); 267 | } 268 | 269 | /// 270 | /// Assert that adding multiple currencies to Moneybags happens correctly 271 | /// 272 | /// 273 | [Test] 274 | public void SimpleBagAdd() 275 | { 276 | // [14 CHF] + {[12 CHF][7 USD]} == {[26 CHF][7 USD]} 277 | Money[] bag = { new Money(26, "CHF"), new Money(7, "USD") }; 278 | var expected = new MoneyBag(bag); 279 | Assert.That(f14CHF.Add(fMB1), Is.EqualTo(expected)); 280 | } 281 | 282 | /// 283 | /// Assert that multiplying currency in Money happens correctly 284 | /// 285 | /// 286 | [Test] 287 | public void SimpleMultiply() 288 | { 289 | // [14 CHF] *2 == [28 CHF] 290 | var expected = new Money(28, "CHF"); 291 | Assert.That(f14CHF.Multiply(2), Is.EqualTo(expected)); 292 | } 293 | 294 | /// 295 | /// Assert that negating(positive to negative values) currency in Money happens correctly 296 | /// 297 | /// 298 | [Test] 299 | public void SimpleNegate() 300 | { 301 | // [14 CHF] negate == [-14 CHF] 302 | var expected = new Money(-14, "CHF"); 303 | Assert.That(f14CHF.Negate(), Is.EqualTo(expected)); 304 | } 305 | 306 | /// 307 | /// Assert that removing currency from Money happens correctly 308 | /// 309 | /// 310 | [Test] 311 | public void SimpleSubtract() 312 | { 313 | // [14 CHF] - [12 CHF] == [2 CHF] 314 | var expected = new Money(2, "CHF"); 315 | Assert.That(f14CHF.Subtract(f12CHF), Is.EqualTo(expected)); 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /syntax/AssertSyntaxTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using NUnit.Framework; 3 | using NUnit.Framework.Legacy; 4 | 5 | namespace AssertSyntax; 6 | 7 | /// 8 | /// This test fixture attempts to exercise all the syntactic 9 | /// variations of Assert without getting into failures, errors 10 | /// or corner cases. Thus, some of the tests may be duplicated 11 | /// in other fixtures. 12 | /// 13 | /// Each test performs the same operations using the classic 14 | /// syntax (if available) and the new syntax in both the 15 | /// helper-based and inherited forms. 16 | /// 17 | /// This Fixture will eventually be duplicated in other 18 | /// supported languages. 19 | /// 20 | [TestFixture] 21 | public class AssertSyntaxTests 22 | { 23 | #region Simple Constraint Tests 24 | [Test] 25 | public void IsNull() 26 | { 27 | object nada = null; 28 | 29 | // Constraint Syntax 30 | Assert.That(nada, Is.Null); 31 | 32 | // Classic syntax 33 | ClassicAssert.IsNull(nada); 34 | } 35 | 36 | [Test] 37 | public void IsNotNull() 38 | { 39 | int? theAnswer = 42; 40 | 41 | // Constraint Syntax 42 | Assert.That(theAnswer, Is.Not.Null); 43 | 44 | // Classic syntax 45 | ClassicAssert.IsNotNull(42); 46 | } 47 | 48 | [Test] 49 | public void IsTrue() 50 | { 51 | // Constraint Syntax 52 | Assert.That(2 + 2 == 4, Is.True); 53 | Assert.That(2 + 2 == 4); 54 | 55 | // Classic syntax 56 | ClassicAssert.IsTrue(2 + 2 == 4); 57 | } 58 | 59 | [Test] 60 | public void IsFalse() 61 | { 62 | // Constraint Syntax 63 | Assert.That(2 + 2 == 5, Is.False); 64 | 65 | // Classic syntax 66 | ClassicAssert.IsFalse(2 + 2 == 5); 67 | } 68 | 69 | [Test] 70 | public void IsNaN() 71 | { 72 | var d = double.NaN; 73 | var f = float.NaN; 74 | 75 | // Constraint Syntax 76 | Assert.That(d, Is.NaN); 77 | Assert.That(f, Is.NaN); 78 | 79 | // Classic syntax 80 | ClassicAssert.IsNaN(d); 81 | ClassicAssert.IsNaN(f); 82 | } 83 | 84 | [Test] 85 | public void EmptyStringTests() 86 | { 87 | // Constraint Syntax 88 | Assert.That("", Is.Empty); 89 | Assert.That("Hello!", Is.Not.Empty); 90 | 91 | // Classic syntax 92 | ClassicAssert.IsEmpty(""); 93 | ClassicAssert.IsNotEmpty("Hello!"); 94 | } 95 | 96 | [Test] 97 | public void EmptyCollectionTests() 98 | { 99 | // Constraint Syntax 100 | Assert.That(new bool[0], Is.Empty); 101 | Assert.That(new[] { 1, 2, 3 }, Is.Not.Empty); 102 | 103 | // Classic syntax 104 | ClassicAssert.IsEmpty(new bool[0]); 105 | ClassicAssert.IsNotEmpty(new[] { 1, 2, 3 }); 106 | } 107 | #endregion 108 | 109 | #region TypeConstraint Tests 110 | [Test] 111 | public void ExactTypeTests() 112 | { 113 | 114 | // Constraint Syntax 115 | Assert.That("Hello", Is.TypeOf(typeof(string))); 116 | Assert.That("Hello", Is.Not.TypeOf(typeof(int))); 117 | 118 | // Classic syntax workarounds 119 | ClassicAssert.AreEqual(typeof(string), "Hello".GetType()); 120 | ClassicAssert.AreEqual("System.String", "Hello".GetType().FullName); 121 | ClassicAssert.AreNotEqual(typeof(int), "Hello".GetType()); 122 | ClassicAssert.AreNotEqual("System.Int32", "Hello".GetType().FullName); 123 | } 124 | 125 | [Test] 126 | public void InstanceOfTests() 127 | { 128 | // Constraint Syntax 129 | Assert.That("Hello", Is.InstanceOf(typeof(string))); 130 | Assert.That(5, Is.Not.InstanceOf(typeof(string))); 131 | 132 | // Classic syntax 133 | ClassicAssert.IsInstanceOf(typeof(string), "Hello"); 134 | ClassicAssert.IsNotInstanceOf(typeof(string), 5); 135 | } 136 | 137 | [Test] 138 | public void AssignableFromTypeTests() 139 | { 140 | // Constraint Syntax 141 | Assert.That("Hello", Is.AssignableFrom(typeof(string))); 142 | Assert.That(5, Is.Not.AssignableFrom(typeof(string))); 143 | 144 | // Classic syntax 145 | ClassicAssert.IsAssignableFrom(typeof(string), "Hello"); 146 | ClassicAssert.IsNotAssignableFrom(typeof(string), 5); 147 | } 148 | #endregion 149 | 150 | #region StringConstraint Tests 151 | [Test] 152 | public void SubstringTests() 153 | { 154 | var phrase = "Hello World!"; 155 | var array = new[] { "abc", "bad", "dba" }; 156 | 157 | // Constraint Syntax 158 | Assert.That(phrase, Does.Contain("World")); 159 | // Only available using new syntax 160 | Assert.That(phrase, Does.Not.Contain("goodbye")); 161 | Assert.That(phrase, Does.Contain("WORLD").IgnoreCase); 162 | Assert.That(phrase, Does.Not.Contain("BYE").IgnoreCase); 163 | Assert.That(array, Is.All.Contains("b")); 164 | 165 | // Classic Syntax 166 | StringAssert.Contains("World", phrase); 167 | } 168 | 169 | [Test] 170 | public void StartsWithTests() 171 | { 172 | var phrase = "Hello World!"; 173 | var greetings = new[] { "Hello!", "Hi!", "Hola!" }; 174 | 175 | // Constraint Syntax 176 | Assert.That(phrase, Does.StartWith("Hello")); 177 | // Only available using new syntax 178 | Assert.That(phrase, Does.Not.StartWith("Hi!")); 179 | Assert.That(phrase, Does.StartWith("HeLLo").IgnoreCase); 180 | Assert.That(phrase, Does.Not.StartWith("HI").IgnoreCase); 181 | Assert.That(greetings, Is.All.StartsWith("h").IgnoreCase); 182 | 183 | // Classic syntax 184 | StringAssert.StartsWith("Hello", phrase); 185 | } 186 | 187 | [Test] 188 | public void EndsWithTests() 189 | { 190 | var phrase = "Hello World!"; 191 | var greetings = new[] { "Hello!", "Hi!", "Hola!" }; 192 | 193 | // Constraint Syntax 194 | Assert.That(phrase, Does.EndWith("!")); 195 | // Only available using new syntax 196 | Assert.That(phrase, Does.Not.EndWith("?")); 197 | Assert.That(phrase, Does.EndWith("WORLD!").IgnoreCase); 198 | Assert.That(greetings, Is.All.EndsWith("!")); 199 | 200 | // Classic Syntax 201 | StringAssert.EndsWith("!", phrase); 202 | } 203 | 204 | [Test] 205 | public void EqualIgnoringCaseTests() 206 | { 207 | var phrase = "Hello World!"; 208 | 209 | // Constraint Syntax 210 | Assert.That(phrase, Is.EqualTo("hello world!").IgnoreCase); 211 | //Only available using new syntax 212 | Assert.That(phrase, Is.Not.EqualTo("goodbye world!").IgnoreCase); 213 | Assert.That(new[] { "Hello", "World" }, 214 | Is.EqualTo(new object[] { "HELLO", "WORLD" }).IgnoreCase); 215 | Assert.That(new[] { "HELLO", "Hello", "hello" }, 216 | Is.All.EqualTo("hello").IgnoreCase); 217 | 218 | // Classic syntax 219 | StringAssert.AreEqualIgnoringCase("hello world!", phrase); 220 | } 221 | 222 | [Test] 223 | public void RegularExpressionTests() 224 | { 225 | var phrase = "Now is the time for all good men to come to the aid of their country."; 226 | var quotes = new[] { "Never say never", "It's never too late", "Nevermore!" }; 227 | 228 | // Constraint Syntax 229 | Assert.That(phrase, Does.Match("all good men")); 230 | Assert.That(phrase, Does.Match("Now.*come")); 231 | // Only available using new syntax 232 | Assert.That(phrase, Does.Not.Match("all.*men.*good")); 233 | Assert.That(phrase, Does.Match("ALL").IgnoreCase); 234 | Assert.That(quotes, Is.All.Matches("never").IgnoreCase); 235 | 236 | // Classic syntax 237 | StringAssert.IsMatch("all good men", phrase); 238 | StringAssert.IsMatch("Now.*come", phrase); 239 | } 240 | #endregion 241 | 242 | #region Equality Tests 243 | [Test] 244 | public void EqualityTests() 245 | { 246 | var i3 = new[] { 1, 2, 3 }; 247 | var d3 = new[] { 1.0, 2.0, 3.0 }; 248 | var iunequal = new[] { 1, 3, 2 }; 249 | 250 | // Constraint Syntax 251 | Assert.That(2 + 2, Is.EqualTo(4)); 252 | Assert.That(2 + 2 == 4); 253 | Assert.That(i3, Is.EqualTo(d3)); 254 | Assert.That(2 + 2, Is.Not.EqualTo(5)); 255 | Assert.That(i3, Is.Not.EqualTo(iunequal)); 256 | 257 | // Classic Syntax 258 | ClassicAssert.AreEqual(4, 2 + 2); 259 | ClassicAssert.AreEqual(i3, d3); 260 | ClassicAssert.AreNotEqual(5, 2 + 2); 261 | ClassicAssert.AreNotEqual(i3, iunequal); 262 | } 263 | 264 | [Test] 265 | public void EqualityTestsWithTolerance() 266 | { 267 | // Constraint Syntax 268 | Assert.That(4.99d, Is.EqualTo(5.0d).Within(0.05d)); 269 | Assert.That(4.0d, Is.Not.EqualTo(5.0d).Within(0.5d)); 270 | Assert.That(4.99f, Is.EqualTo(5.0f).Within(0.05f)); 271 | Assert.That(4.99m, Is.EqualTo(5.0m).Within(0.05m)); 272 | Assert.That(3999999999u, Is.EqualTo(4000000000u).Within(5u)); 273 | Assert.That(499, Is.EqualTo(500).Within(5)); 274 | Assert.That(4999999999L, Is.EqualTo(5000000000L).Within(5L)); 275 | Assert.That(5999999999ul, Is.EqualTo(6000000000ul).Within(5ul)); 276 | 277 | // CLassic syntax 278 | ClassicAssert.AreEqual(5.0d, 4.99d, 0.05d); 279 | ClassicAssert.AreEqual(5.0f, 4.99f, 0.05f); 280 | } 281 | 282 | [Test] 283 | public void EqualityTestsWithTolerance_MixedFloatAndDouble() 284 | { 285 | // Bug Fix 1743844 286 | Assert.That(2.20492d, Is.EqualTo(2.2d).Within(0.01f), 287 | "Double actual, Double expected, Single tolerance"); 288 | Assert.That(2.20492d, Is.EqualTo(2.2f).Within(0.01d), 289 | "Double actual, Single expected, Double tolerance"); 290 | Assert.That(2.20492d, Is.EqualTo(2.2f).Within(0.01f), 291 | "Double actual, Single expected, Single tolerance"); 292 | Assert.That(2.20492f, Is.EqualTo(2.2f).Within(0.01d), 293 | "Single actual, Single expected, Double tolerance"); 294 | Assert.That(2.20492f, Is.EqualTo(2.2d).Within(0.01d), 295 | "Single actual, Double expected, Double tolerance"); 296 | Assert.That(2.20492f, Is.EqualTo(2.2d).Within(0.01f), 297 | "Single actual, Double expected, Single tolerance"); 298 | } 299 | 300 | [Test] 301 | public void EqualityTestsWithTolerance_MixingTypesGenerally() 302 | { 303 | // Extending tolerance to all numeric types 304 | Assert.That(202d, Is.EqualTo(200d).Within(2), 305 | "Double actual, Double expected, int tolerance"); 306 | Assert.That(4.87m, Is.EqualTo(5).Within(.25), 307 | "Decimal actual, int expected, Double tolerance"); 308 | Assert.That(4.87m, Is.EqualTo(5ul).Within(1), 309 | "Decimal actual, ulong expected, int tolerance"); 310 | Assert.That(487, Is.EqualTo(500).Within(25), 311 | "int actual, int expected, int tolerance"); 312 | Assert.That(487u, Is.EqualTo(500).Within(25), 313 | "uint actual, int expected, int tolerance"); 314 | Assert.That(487L, Is.EqualTo(500).Within(25), 315 | "long actual, int expected, int tolerance"); 316 | Assert.That(487ul, Is.EqualTo(500).Within(25), 317 | "ulong actual, int expected, int tolerance"); 318 | } 319 | #endregion 320 | 321 | #region Comparison Tests 322 | [Test] 323 | public void ComparisonTests() 324 | { 325 | // Constraint Syntax 326 | Assert.That(7, Is.GreaterThan(3)); 327 | Assert.That(7, Is.GreaterThanOrEqualTo(3)); 328 | Assert.That(7, Is.AtLeast(3)); 329 | Assert.That(7, Is.GreaterThanOrEqualTo(7)); 330 | Assert.That(7, Is.AtLeast(7)); 331 | 332 | // Classic Syntax 333 | ClassicAssert.Greater(7, 3); 334 | ClassicAssert.GreaterOrEqual(7, 3); 335 | ClassicAssert.GreaterOrEqual(7, 7); 336 | 337 | // Constraint Syntax 338 | Assert.That(3, Is.LessThan(7)); 339 | Assert.That(3, Is.LessThanOrEqualTo(7)); 340 | Assert.That(3, Is.AtMost(7)); 341 | Assert.That(3, Is.LessThanOrEqualTo(3)); 342 | Assert.That(3, Is.AtMost(3)); 343 | 344 | 345 | // Classic syntax 346 | ClassicAssert.Less(3, 7); 347 | ClassicAssert.LessOrEqual(3, 7); 348 | ClassicAssert.LessOrEqual(3, 3); 349 | } 350 | #endregion 351 | 352 | #region Collection Tests 353 | [Test] 354 | public void AllItemsTests() 355 | { 356 | var ints = new object[] { 1, 2, 3, 4 }; 357 | var doubles = new object[] { 0.99, 2.1, 3.0, 4.05 }; 358 | var strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; 359 | 360 | // Constraint Syntax 361 | Assert.That(ints, Is.All.Not.Null); 362 | Assert.That(ints, Has.None.Null); 363 | Assert.That(ints, Is.All.InstanceOf(typeof(int))); 364 | Assert.That(ints, Has.All.InstanceOf(typeof(int))); 365 | Assert.That(strings, Is.All.InstanceOf(typeof(string))); 366 | Assert.That(strings, Has.All.InstanceOf(typeof(string))); 367 | Assert.That(ints, Is.Unique); 368 | // Only available using new syntax 369 | Assert.That(strings, Is.Not.Unique); 370 | Assert.That(ints, Is.All.GreaterThan(0)); 371 | Assert.That(ints, Has.All.GreaterThan(0)); 372 | Assert.That(ints, Has.None.LessThanOrEqualTo(0)); 373 | Assert.That(strings, Is.All.Contains("a")); 374 | Assert.That(strings, Has.All.Contains("a")); 375 | Assert.That(strings, Has.Some.StartsWith("ba")); 376 | Assert.That(strings, Has.Some.Property("Length").EqualTo(3)); 377 | Assert.That(strings, Has.Some.StartsWith("BA").IgnoreCase); 378 | Assert.That(doubles, Has.Some.EqualTo(1.0).Within(.05)); 379 | 380 | // Classic syntax 381 | CollectionAssert.AllItemsAreNotNull(ints); 382 | CollectionAssert.AllItemsAreInstancesOfType(ints, typeof(int)); 383 | CollectionAssert.AllItemsAreInstancesOfType(strings, typeof(string)); 384 | CollectionAssert.AllItemsAreUnique(ints); 385 | 386 | } 387 | 388 | [Test] 389 | public void SomeItemTests() 390 | { 391 | var mixed = new object[] { 1, 2, "3", null, "four", 100 }; 392 | var strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; 393 | 394 | // Not available using the classic syntax 395 | 396 | // Constraint Syntax 397 | Assert.That(mixed, Has.Some.Null); 398 | Assert.That(mixed, Has.Some.InstanceOf(typeof(int))); 399 | Assert.That(mixed, Has.Some.InstanceOf(typeof(string))); 400 | Assert.That(strings, Has.Some.StartsWith("ba")); 401 | Assert.That(strings, Has.Some.Not.StartsWith("ba")); 402 | } 403 | 404 | [Test] 405 | public void NoItemTests() 406 | { 407 | var ints = new object[] { 1, 2, 3, 4, 5 }; 408 | var strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; 409 | 410 | // Not available using the classic syntax 411 | 412 | // Constraint Syntax 413 | Assert.That(ints, Has.None.Null); 414 | Assert.That(ints, Has.None.InstanceOf(typeof(string))); 415 | Assert.That(ints, Has.None.GreaterThan(99)); 416 | Assert.That(strings, Has.None.StartsWith("qu")); 417 | } 418 | 419 | [Test] 420 | public void CollectionContainsTests() 421 | { 422 | var iarray = new[] { 1, 2, 3 }; 423 | var sarray = new[] { "a", "b", "c" }; 424 | 425 | // Constraint Syntax 426 | Assert.That(iarray, Has.Member(3)); 427 | Assert.That(sarray, Has.Member("b")); 428 | Assert.That(sarray, Has.No.Member("x")); 429 | // Showing that Contains uses NUnit equality 430 | Assert.That(iarray, Has.Member(1.0d)); 431 | 432 | // Only available using the new syntax 433 | // Note that EqualTo and SameAs do NOT give 434 | // identical results to Contains because 435 | // Contains uses Object.Equals() 436 | Assert.That(iarray, Has.Some.EqualTo(3)); 437 | Assert.That(iarray, Has.Member(3)); 438 | Assert.That(sarray, Has.Some.EqualTo("b")); 439 | Assert.That(sarray, Has.None.EqualTo("x")); 440 | Assert.That(iarray, Has.None.SameAs(1.0d)); 441 | Assert.That(iarray, Has.All.LessThan(10)); 442 | Assert.That(sarray, Has.All.Length.EqualTo(1)); 443 | Assert.That(sarray, Has.None.Property("Length").GreaterThan(3)); 444 | 445 | // Classic syntax 446 | ClassicAssert.Contains(3, iarray); 447 | ClassicAssert.Contains("b", sarray); 448 | CollectionAssert.Contains(iarray, 3); 449 | CollectionAssert.Contains(sarray, "b"); 450 | CollectionAssert.DoesNotContain(sarray, "x"); 451 | // Showing that Contains uses NUnit equality 452 | CollectionAssert.Contains(iarray, 1.0d); 453 | 454 | 455 | } 456 | 457 | [Test] 458 | public void CollectionEquivalenceTests() 459 | { 460 | var ints1to5 = new[] { 1, 2, 3, 4, 5 }; 461 | var twothrees = new[] { 1, 2, 3, 3, 4, 5 }; 462 | var twofours = new[] { 1, 2, 3, 4, 4, 5 }; 463 | 464 | // Constraint Syntax 465 | Assert.That(new[] { 2, 1, 4, 3, 5 }, Is.EquivalentTo(ints1to5)); 466 | Assert.That(new[] { 2, 2, 4, 3, 5 }, Is.Not.EquivalentTo(ints1to5)); 467 | Assert.That(new[] { 2, 4, 3, 5 }, Is.Not.EquivalentTo(ints1to5)); 468 | Assert.That(new[] { 2, 2, 1, 1, 4, 3, 5 }, Is.Not.EquivalentTo(ints1to5)); 469 | 470 | // Classic syntax 471 | CollectionAssert.AreEquivalent(new[] { 2, 1, 4, 3, 5 }, ints1to5); 472 | CollectionAssert.AreNotEquivalent(new[] { 2, 2, 4, 3, 5 }, ints1to5); 473 | CollectionAssert.AreNotEquivalent(new[] { 2, 4, 3, 5 }, ints1to5); 474 | CollectionAssert.AreNotEquivalent(new[] { 2, 2, 1, 1, 4, 3, 5 }, ints1to5); 475 | CollectionAssert.AreNotEquivalent(twothrees, twofours); 476 | } 477 | 478 | [Test] 479 | public void SubsetTests() 480 | { 481 | var ints1to5 = new[] { 1, 2, 3, 4, 5 }; 482 | 483 | // Constraint Syntax 484 | Assert.That(new[] { 1, 3, 5 }, Is.SubsetOf(ints1to5)); 485 | Assert.That(new[] { 1, 2, 3, 4, 5 }, Is.SubsetOf(ints1to5)); 486 | Assert.That(new[] { 2, 4, 6 }, Is.Not.SubsetOf(ints1to5)); 487 | 488 | // Classic syntax 489 | CollectionAssert.IsSubsetOf(new[] { 1, 3, 5 }, ints1to5); 490 | CollectionAssert.IsSubsetOf(new[] { 1, 2, 3, 4, 5 }, ints1to5); 491 | CollectionAssert.IsNotSubsetOf(new[] { 2, 4, 6 }, ints1to5); 492 | CollectionAssert.IsNotSubsetOf(new[] { 1, 2, 2, 2, 5 }, ints1to5); 493 | 494 | } 495 | #endregion 496 | 497 | #region Property Tests 498 | [Test] 499 | public void PropertyTests() 500 | { 501 | string[] array = { "abc", "bca", "xyz", "qrs" }; 502 | string[] array2 = { "a", "ab", "abc" }; 503 | var list = new ArrayList(array); 504 | 505 | // Not available using the classic syntax 506 | 507 | // Constraint Syntax 508 | Assert.That(list, Has.Property("Count")); 509 | Assert.That(list, Has.No.Property("Length")); 510 | 511 | Assert.That("Hello", Has.Length.EqualTo(5)); 512 | Assert.That("Hello", Has.Length.LessThan(10)); 513 | Assert.That("Hello", Has.Property("Length").EqualTo(5)); 514 | Assert.That("Hello", Has.Property("Length").GreaterThan(3)); 515 | 516 | Assert.That(array, Has.Property("Length").EqualTo(4)); 517 | Assert.That(array, Has.Length.EqualTo(4)); 518 | Assert.That(array, Has.Property("Length").LessThan(10)); 519 | 520 | Assert.That(array, Has.All.Property("Length").EqualTo(3)); 521 | Assert.That(array, Has.All.Length.EqualTo(3)); 522 | Assert.That(array, Is.All.Length.EqualTo(3)); 523 | Assert.That(array, Has.All.Property("Length").EqualTo(3)); 524 | Assert.That(array, Is.All.Property("Length").EqualTo(3)); 525 | 526 | Assert.That(array2, Has.Some.Property("Length").EqualTo(2)); 527 | Assert.That(array2, Has.Some.Length.EqualTo(2)); 528 | Assert.That(array2, Has.Some.Property("Length").GreaterThan(2)); 529 | 530 | Assert.That(array2, Is.Not.Property("Length").EqualTo(4)); 531 | Assert.That(array2, Is.Not.Length.EqualTo(4)); 532 | Assert.That(array2, Has.No.Property("Length").GreaterThan(3)); 533 | 534 | Assert.That(list, Has.Count.EqualTo(4)); 535 | } 536 | #endregion 537 | 538 | #region Not Tests 539 | [Test] 540 | public void NotTests() 541 | { 542 | int? theAnswer = 42; 543 | // Not available using the classic syntax 544 | 545 | // Constraint Syntax 546 | Assert.That(theAnswer, Is.Not.Null); 547 | Assert.That(theAnswer, Is.Not.True); 548 | Assert.That(theAnswer, Is.Not.False); 549 | Assert.That(2.5, Is.Not.NaN); 550 | Assert.That(2 + 2, Is.Not.EqualTo(3)); 551 | Assert.That(2 + 2, Is.Not.Not.EqualTo(4)); 552 | Assert.That(2 + 2, Is.Not.Not.Not.EqualTo(5)); 553 | } 554 | #endregion 555 | 556 | #region Operator Tests 557 | [Test] 558 | public void NotOperator() 559 | { 560 | // The ! operator is only available in the new syntax 561 | Assert.That(42, !Is.Null); 562 | } 563 | 564 | [Test] 565 | public void AndOperator() 566 | { 567 | // The & operator is only available in the new syntax 568 | Assert.That(7, Is.GreaterThan(5) & Is.LessThan(10)); 569 | } 570 | 571 | [Test] 572 | public void OrOperator() 573 | { 574 | // The | operator is only available in the new syntax 575 | Assert.That(3, Is.LessThan(5) | Is.GreaterThan(10)); 576 | } 577 | 578 | [Test] 579 | public void ComplexTests() 580 | { 581 | int? theAnswer = 7; 582 | Assert.That(theAnswer, Is.Not.Null & Is.Not.LessThan(5) & Is.Not.GreaterThan(10)); 583 | 584 | Assert.That(theAnswer, !Is.Null & !Is.LessThan(5) & !Is.GreaterThan(10)); 585 | 586 | // No longer works at all under 3.0 587 | // TODO: Evaluate why we wanted to use null in this setting in the first place 588 | #if false 589 | // TODO: Remove #if when mono compiler can handle null 590 | #if MONO 591 | Constraint x = null; 592 | Assert.That(7, !x & !Is.LessThan(5) & !Is.GreaterThan(10)); 593 | Expect(7, !x & !LessThan(5) & !GreaterThan(10)); 594 | #else 595 | Assert.That(7, !(Constraint)null & !Is.LessThan(5) & !Is.GreaterThan(10)); 596 | Expect(7, !(Constraint)null & !LessThan(5) & !GreaterThan(10)); 597 | #endif 598 | #endif 599 | } 600 | #endregion 601 | 602 | #region Invalid Code Tests 603 | // This method contains assertions that should not compile 604 | // You can check by uncommenting it. 605 | //public void WillNotCompile() 606 | //{ 607 | // Assert.That(42, Is.Not); 608 | // Assert.That(42, Is.All); 609 | // Assert.That(42, Is.Null.Not); 610 | // Assert.That(42, Is.Not.Null.GreaterThan(10)); 611 | // Assert.That(42, Is.GreaterThan(10).LessThan(99)); 612 | 613 | // object[] c = new object[0]; 614 | // Assert.That(c, Is.Null.All); 615 | // Assert.That(c, Is.Not.All); 616 | // Assert.That(c, Is.All.Not); 617 | //} 618 | #endregion 619 | 620 | #region Assumptions 621 | 622 | [Test] 623 | public void PositiveAssumption() 624 | { 625 | Assume.That(true); 626 | 627 | Assert.Pass("This will be executed because of the assumption."); 628 | } 629 | 630 | [Test] 631 | public void NegativeAssumption() 632 | { 633 | Assume.That(false); 634 | 635 | Assert.Fail("This will not be executed because of the assumption."); 636 | } 637 | 638 | #endregion 639 | 640 | #region Warnings 641 | 642 | [Test] 643 | public void PositiveWarning() 644 | { 645 | Warn.If(true, "This will emit a warning"); 646 | Warn.Unless(false, "This will emit a warning"); 647 | 648 | Assert.Pass("This test passes despite the warnings."); 649 | } 650 | 651 | [Test] 652 | public void NegativeWarning() 653 | { 654 | Warn.If(false, "This will not emit a warning"); 655 | Warn.Unless(true, "This will not emit a warning"); 656 | 657 | Assert.Pass("This test passes despite the warnings."); 658 | } 659 | 660 | #endregion 661 | } --------------------------------------------------------------------------------