Skip to content

Commit

Permalink
Support for NUnit3 (Lifecycle) (#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattwhitfield authored Nov 6, 2023
1 parent acf6108 commit dae7a94
Show file tree
Hide file tree
Showing 22 changed files with 240 additions and 19 deletions.
114 changes: 114 additions & 0 deletions docs/examples/FrameworksNUnitLifecycleNSubstitute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Frameworks - NUnit 3 (Lifecycle) & NSubstitute
Demonstrates how tests are generated using NUnit 3 (Lifecycle) for the test framework and NSubstitute for the mocking framework

### Source Type(s)
``` csharp
public interface IDependency
{
int Method();
}

public class TestClass
{
IDependency _dependency;

public TestClass(IDependency dependency)
{
_dependency = dependency;
}

public void SomeMethod(string methodName, int methodValue)
{
var x = _dependency.Method();
System.Console.WriteLine("Testing this" + x);
}

public System.Threading.Tasks.Task<int> SomeAsyncMethod(string methodName, int methodValue)
{
System.Console.WriteLine("Testing this");
return System.Threading.Tasks.Task.FromResult(0);
}
}

```

### Generated Tests
``` csharp
[TestFixture, FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
public class TestClassTests
{
private TestClass _testClass;
private IDependency _dependency;

public TestClassTests()
{
_dependency = Substitute.For<IDependency>();
_testClass = new TestClass(_dependency);
}

[Test]
public void CanConstruct()
{
// Act
var instance = new TestClass(_dependency);

// Assert
Assert.That(instance, Is.Not.Null);
}

[Test]
public void CannotConstructWithNullDependency()
{
Assert.Throws<ArgumentNullException>(() => new TestClass(default(IDependency)));
}

[Test]
public void CanCallSomeMethod()
{
// Arrange
var methodName = "TestValue237820880";
var methodValue = 1002897798;

_dependency.Method().Returns(534011718);

// Act
_testClass.SomeMethod(methodName, methodValue);

// Assert
_dependency.Received().Method();

Assert.Fail("Create or modify test");
}

[TestCase(null)]
[TestCase("")]
[TestCase(" ")]
public void CannotCallSomeMethodWithInvalidMethodName(string value)
{
Assert.Throws<ArgumentNullException>(() => _testClass.SomeMethod(value, 1657007234));
}

[Test]
public async Task CanCallSomeAsyncMethod()
{
// Arrange
var methodName = "TestValue1412011072";
var methodValue = 929393559;

// Act
var result = await _testClass.SomeAsyncMethod(methodName, methodValue);

// Assert
Assert.Fail("Create or modify test");
}

[TestCase(null)]
[TestCase("")]
[TestCase(" ")]
public void CannotCallSomeAsyncMethodWithInvalidMethodName(string value)
{
Assert.ThrowsAsync<ArgumentNullException>(() => _testClass.SomeAsyncMethod(value, 760389092));
}
}

```
1 change: 1 addition & 0 deletions docs/examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ This section contains examples of the output that Unitverse outputs, refreshed e
| [Frameworks - MSTest & Moq](FrameworksMsTestMoq.md) | Demonstrates how tests are generated using MsTest for the test framework and Moq for the mocking framework |
| [Frameworks - MSTest & Moq (with Moq.AutoMock)](FrameworksMsTestMoqAutoMock.md) | Demonstrates how tests are generated using MsTest for the test framework and Moq for the mocking framework, using Moq.AutoMock for object creation |
| [Frameworks - NUnit 3 & FakeItEasy](FrameworksNUnitFakeItEasy.md) | Demonstrates how tests are generated using NUnit 3 for the test framework and FakeItEasy for the mocking framework |
| [Frameworks - NUnit 3 (Lifecycle) & NSubstitute](FrameworksNUnitLifecycleNSubstitute.md) | Demonstrates how tests are generated using NUnit 3 (Lifecycle) for the test framework and NSubstitute for the mocking framework |
| [Frameworks - XUnit & JustMock](FrameworksXUnitJustMock.md) | Demonstrates how tests are generated using XUnit for the test framework and JustMock for the mocking framework |
| [Frameworks - XUnit & NSubstitute](FrameworksXUnitNSubstitute.md) | Demonstrates how tests are generated using XUnit for the test framework and NSubstitute for the mocking framework |
| [Generic Methods](GenericMethod.md) | Demonstrates how Unitverse generates tests for generic methods |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public void CanGetSingleThreadedApartmentAttribute(TestFrameworkTypes frameworkT
public void CanGetTestClassAttribute(TestFrameworkTypes frameworkTypes, string expected)
{
var testClass = CreateFramework(frameworkTypes);
Assert.That(testClass.TestClassAttribute, Is.EqualTo(expected));
Assert.That(testClass.TestClassAttributes?.FirstOrDefault()?.Name.ToString() ?? string.Empty, Is.EqualTo(expected));
}

[TestCaseSource(nameof(Targets))]
Expand Down
5 changes: 3 additions & 2 deletions src/Unitverse.Core.Tests/UnitTestGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
using Expression = System.Linq.Expressions.Expression;

[TestFixture]
[FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
public class UnitTestGeneratorTests
{
// useAutoFixture, useAutoFixtureForMocking, useFieldForAutoFixture
Expand Down Expand Up @@ -71,7 +72,7 @@ public static IEnumerable<object[]> TestClassResourceNames
entryKeys.Add(entry.Key.ToString());
}

var frameworks = new object[] { TestFrameworkTypes.MsTest, TestFrameworkTypes.NUnit3, TestFrameworkTypes.XUnit };
var frameworks = new object[] { TestFrameworkTypes.MsTest, TestFrameworkTypes.NUnit3, TestFrameworkTypes.NUnit3Lifecycle, TestFrameworkTypes.XUnit };
var mocks = new object[] { MockingFrameworkType.Moq, MockingFrameworkType.NSubstitute, MockingFrameworkType.FakeItEasy, MockingFrameworkType.MoqAutoMock, MockingFrameworkType.JustMock };

#if VS2019
Expand Down Expand Up @@ -362,7 +363,7 @@ private static IEnumerable<PortableExecutableReference> GetReferences(TestFramew
yield return MetadataReference.CreateFromFile(typeof(Xunit.Assert).Assembly.Location);
}

if ((testFrameworkTypes & (TestFrameworkTypes.NUnit3 | TestFrameworkTypes.NUnit2)) > 0)
if ((testFrameworkTypes & (TestFrameworkTypes.NUnit3Lifecycle | TestFrameworkTypes.NUnit3 | TestFrameworkTypes.NUnit2)) > 0)
{
yield return MetadataReference.CreateFromFile(typeof(TestFixtureAttribute).Assembly.Location);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Unitverse.Core/Assets/PropertyTesterAsset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public string Content(string targetNamespace, TestFrameworkTypes testFrameworkTy
return AssetResources.PropertyTesterXUnit.Replace("%targetNamespace%", targetNamespace);
}

if ((testFrameworkTypes & (TestFrameworkTypes.NUnit2 | TestFrameworkTypes.NUnit3)) > 0)
if ((testFrameworkTypes & (TestFrameworkTypes.NUnit2 | TestFrameworkTypes.NUnit3 | TestFrameworkTypes.NUnit3Lifecycle)) > 0)
{
return AssetResources.PropertyTesterNUnit.Replace("%targetNamespace%", targetNamespace);
}
Expand Down
1 change: 1 addition & 0 deletions src/Unitverse.Core/Frameworks/FrameworkPackageProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static IEnumerable<INugetPackageReference> Get(IGenerationOptions generat
yield return new NugetPackageReference("NUnitTestAdapter", null);
break;
case TestFrameworkTypes.NUnit3:
case TestFrameworkTypes.NUnit3Lifecycle:
yield return new NugetPackageReference("nunit", null);
yield return new NugetPackageReference("NUnit3TestAdapter", null);
break;
Expand Down
5 changes: 5 additions & 0 deletions src/Unitverse.Core/Frameworks/FrameworkSetFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ private static IExtendedTestFramework CreateTestFramework(IUnitTestGeneratorOpti
return new NUnit3TestFramework(options);
}

if ((testFrameworkTypes & TestFrameworkTypes.NUnit3Lifecycle) > 0)
{
return new NUnit3LifeCycleFramework(options);
}

if ((testFrameworkTypes & TestFrameworkTypes.NUnit2) > 0)
{
return new NUnit2TestFramework(options);
Expand Down
3 changes: 2 additions & 1 deletion src/Unitverse.Core/Frameworks/ITestFramework.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Unitverse.Core.Frameworks
{
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp.Syntax;

public interface ITestFramework : IAssertionFramework
Expand All @@ -8,6 +9,6 @@ public interface ITestFramework : IAssertionFramework

AttributeSyntax? SingleThreadedApartmentAttribute { get; }

string TestClassAttribute { get; }
IEnumerable<AttributeSyntax>? TestClassAttributes { get; }
}
}
2 changes: 1 addition & 1 deletion src/Unitverse.Core/Frameworks/Test/MsTestTestFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public MsTestTestFramework(IUnitTestGeneratorOptions options)

public AttributeSyntax? SingleThreadedApartmentAttribute => null;

public string TestClassAttribute => "TestClass";
public IEnumerable<AttributeSyntax> TestClassAttributes => new[] { Generate.Attribute("TestClass") };

protected override string TestAttributeName => "TestMethod";

Expand Down
27 changes: 27 additions & 0 deletions src/Unitverse.Core/Frameworks/Test/NUnit3LifeCycleFramework.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Unitverse.Core.Frameworks.Test
{
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Unitverse.Core.Helpers;
using Unitverse.Core.Options;

public class NUnit3LifeCycleFramework : NUnit3TestFramework
{
public NUnit3LifeCycleFramework(IUnitTestGeneratorOptions options)
: base(options)
{
}

public override IEnumerable<AttributeSyntax> TestClassAttributes => new[]
{
Generate.Attribute("TestFixture"),
Generate.Attribute("FixtureLifeCycle", Generate.MemberAccess("LifeCycle", "InstancePerTestCase")),
};

protected override BaseMethodDeclarationSyntax CreateSetupMethodSyntax(string targetTypeName)
{
return SyntaxFactory.ConstructorDeclaration(SyntaxFactory.Identifier(targetTypeName)).AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
}
}
}
1 change: 1 addition & 0 deletions src/Unitverse.Core/Frameworks/Test/NUnit3TestFramework.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Unitverse.Core.Frameworks.Test
{
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Unitverse.Core.Helpers;
using Unitverse.Core.Options;
Expand Down
2 changes: 1 addition & 1 deletion src/Unitverse.Core/Frameworks/Test/NUnitTestFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protected NUnitTestFramework(IUnitTestGeneratorOptions options)

public abstract AttributeSyntax SingleThreadedApartmentAttribute { get; }

public string TestClassAttribute => "TestFixture";
public virtual IEnumerable<AttributeSyntax> TestClassAttributes => new[] { Generate.Attribute("TestFixture") };

protected override string TestAttributeName => "Test";

Expand Down
3 changes: 2 additions & 1 deletion src/Unitverse.Core/Frameworks/Test/XUnitTestFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Unitverse.Core.Helpers;
Expand All @@ -20,7 +21,7 @@ public XUnitTestFramework(IUnitTestGeneratorOptions options)

public AttributeSyntax? SingleThreadedApartmentAttribute => null;

public string TestClassAttribute => string.Empty;
public IEnumerable<AttributeSyntax>? TestClassAttributes => null;

protected override string TestAttributeName => "Fact";

Expand Down
5 changes: 5 additions & 0 deletions src/Unitverse.Core/Helpers/Generate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@ public static AttributeListSyntax AsList(this AttributeSyntax attribute)
return SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(attribute));
}

public static AttributeListSyntax AsList(this IEnumerable<AttributeSyntax> attributes)
{
return SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(attributes));
}

public static AttributeSyntax Attribute(string name)
{
if (string.IsNullOrWhiteSpace(name))
Expand Down
2 changes: 2 additions & 0 deletions src/Unitverse.Core/Options/TestFrameworkTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public enum TestFrameworkTypes
MsTest = 4,
[Description("xUnit")]
XUnit = 8,
[Description("NUnit v3 (lifecycle)")]
NUnit3Lifecycle = 16,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ public ClassDeclarationSyntax Create(ClassModel model)
var classDeclaration = SyntaxFactory.ClassDeclaration(targetTypeName);

classDeclaration = classDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
if (!string.IsNullOrWhiteSpace(_frameworkSet.TestFramework.TestClassAttribute))
if (_frameworkSet.TestFramework.TestClassAttributes != null)
{
var testFixtureAtt = Generate.Attribute(_frameworkSet.TestFramework.TestClassAttribute);
classDeclaration = classDeclaration.AddAttributeLists(testFixtureAtt.AsList());
classDeclaration = classDeclaration.AddAttributeLists(_frameworkSet.TestFramework.TestClassAttributes.AsList());
}

classDeclaration = classDeclaration.AddMembers(GenerateConcreteInheritor(model));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ public ClassDeclarationSyntax Create(ClassModel model)
var classDeclaration = SyntaxFactory.ClassDeclaration(targetTypeName);

classDeclaration = classDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
if (!string.IsNullOrWhiteSpace(_frameworkSet.TestFramework.TestClassAttribute))
if (_frameworkSet.TestFramework.TestClassAttributes != null)
{
var testFixtureAtt = Generate.Attribute(_frameworkSet.TestFramework.TestClassAttribute);
classDeclaration = classDeclaration.AddAttributeLists(testFixtureAtt.AsList());
classDeclaration = classDeclaration.AddAttributeLists(_frameworkSet.TestFramework.TestClassAttributes.AsList());
}

var variableDeclaration = SyntaxFactory.VariableDeclaration(model.TypeSyntax)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ public ClassDeclarationSyntax Create(ClassModel model)
classDeclaration = classDeclaration.AddMembers(field);
}

if (!string.IsNullOrWhiteSpace(_frameworkSet.TestFramework.TestClassAttribute))
if (_frameworkSet.TestFramework.TestClassAttributes != null)
{
var testFixtureAtt = Generate.Attribute(_frameworkSet.TestFramework.TestClassAttribute);
classDeclaration = classDeclaration.AddAttributeLists(testFixtureAtt.AsList());
classDeclaration = classDeclaration.AddAttributeLists(_frameworkSet.TestFramework.TestClassAttributes.AsList());
}

return classDeclaration;
Expand Down
29 changes: 28 additions & 1 deletion src/Unitverse.ExampleGenerator/Examples.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Unitverse.ExampleGenerator/Examples.resx
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
<data name="FrameworksNUnitFakeItEasy" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\FrameworksNUnitFakeItEasy.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="FrameworksNUnitLifecycleNSubstitute" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\FrameworksNUnitLifecycleNSubstitute.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="FrameworksXUnitJustMock" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\FrameworksXUnitJustMock.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
Expand Down
Loading

0 comments on commit dae7a94

Please sign in to comment.