Skip to content

Commit

Permalink
chore: Add tests to ensure Command/Queries always returns a Result (#6)
Browse files Browse the repository at this point in the history
* chore: Add tests to ensure Command/Queries always returns a Result

* nit
  • Loading branch information
cbrevik authored Oct 22, 2024
1 parent bd2bf7c commit ac6cd44
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 1 deletion.
50 changes: 49 additions & 1 deletion tests/Core.Tests/ArchitectureTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System.Reflection;
using Core.Tests.Rules;
using FluentAssertions;
using MediatR;
using NetArchTest.Rules;
using Xunit.Abstractions;

namespace Core.Tests;

public class ArchitectureTests()
public class ArchitectureTests(ITestOutputHelper testOutputHelper)
{
private static readonly Assembly ApiAssembly = Assembly.GetAssembly(typeof(Api.Program));

Check warning on line 12 in tests/Core.Tests/ArchitectureTests.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Possible null reference assignment.
private static readonly Assembly InfrastructureAssembly = Assembly.GetAssembly(typeof(Infrastructure.DependencyInjection));

Check warning on line 13 in tests/Core.Tests/ArchitectureTests.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Possible null reference assignment.
Expand All @@ -21,6 +23,8 @@ public void Api_Should_Not_Depend_On_Infrastructure_Except_For_Setting_Up_Depend
.ShouldNot()
.HaveDependencyOn("Infrastructure")
.GetResult();

LogIfFailure(result);

result.IsSuccessful.Should().BeTrue();
}
Expand All @@ -32,6 +36,8 @@ public void Infrastructure_Should_Not_Depend_On_Api()
.ShouldNot()
.HaveDependencyOn("Api")
.GetResult();

LogIfFailure(result);

result.IsSuccessful.Should().BeTrue();
}
Expand All @@ -43,6 +49,8 @@ public void Application_Should_Not_Depend_On_Api_Or_Infrastructure()
.ShouldNot()
.HaveDependencyOnAny("Api", "Infrastructure")
.GetResult();

LogIfFailure(result);

result.IsSuccessful.Should().BeTrue();
}
Expand All @@ -54,7 +62,47 @@ public void Domain_Should_Not_Have_Dependency_On_Any_Of_The_Other_Layers()
.ShouldNot()
.HaveDependencyOnAny("Api", "Infrastructure", "Application")
.GetResult();

LogIfFailure(result);

result.IsSuccessful.Should().BeTrue();
}

[Fact]
public void IRequests_Should_Return_Result_Or_ResultOfT()
{
var requestShouldWrapResultRule = new RequestShouldWrapResultRule();

var result = Types
.InAssembly(ApplicationAssembly)
.That()
.ImplementInterface(typeof(IRequest<>))
.Should()
.MeetCustomRule(requestShouldWrapResultRule)
.GetResult();

LogIfFailure(result);

result.IsSuccessful.Should().BeTrue();
}

[Fact]
public void IRequests_Should_Not_Implement_Plain_Request()
{
var result = Types
.InAssembly(ApplicationAssembly)
.ShouldNot()
.ImplementInterface(typeof(IRequest))
.GetResult();

LogIfFailure(result);
result.IsSuccessful.Should().BeTrue();
}

private void LogIfFailure(TestResult result)
{
if (result.IsSuccessful) return;

testOutputHelper.WriteLine("Types that failed to meet the rule: " + string.Join(", ", result.FailingTypes));
}
}
33 changes: 33 additions & 0 deletions tests/Core.Tests/Rules/RequestShouldWrapResultRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using FluentResults;
using MediatR;
using Mono.Cecil;
using NetArchTest.Rules;

namespace Core.Tests.Rules;

public class RequestShouldWrapResultRule : ICustomRule
{
private static readonly Type ResultType = typeof(Result);
private static readonly Type ResultGenericType = typeof(Result<>);
private static readonly Type RequestGenericType = typeof(IRequest<>);

public bool MeetsRule(TypeDefinition typeDefinition)
{
// Should be a single interface that is IRequest<T>
var requestType = typeDefinition.Interfaces
.Single(i =>
TypeReferenceMatchesType(i.InterfaceType, RequestGenericType))
.InterfaceType as GenericInstanceType;

var responseType = requestType.GenericArguments[0];

Check warning on line 22 in tests/Core.Tests/Rules/RequestShouldWrapResultRule.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.

// Response type should be Result or Result<T>
return TypeReferenceMatchesType(responseType, ResultType)
|| TypeReferenceMatchesType(responseType, ResultGenericType);
}

private static bool TypeReferenceMatchesType(TypeReference typeReference, Type type)
{
return typeReference.Name == type.Name && typeReference.Namespace == type.Namespace;
}
}

0 comments on commit ac6cd44

Please sign in to comment.