Skip to content

Commit c736b51

Browse files
committed
Task<ActionResult<T> action result is now resolved correctly (closes #370)
1 parent f443b31 commit c736b51

File tree

10 files changed

+488
-18
lines changed

10 files changed

+488
-18
lines changed

samples/Blog/Blog.Web/Startup.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Data;
66
using Data.Models;
77
using Infrastructure;
8-
using Services;
98
using Microsoft.AspNetCore.Builder;
109
using Microsoft.AspNetCore.Hosting;
1110
using Microsoft.AspNetCore.Http;
@@ -15,14 +14,15 @@
1514
using Microsoft.Extensions.Configuration;
1615
using Microsoft.Extensions.DependencyInjection;
1716
using Microsoft.Extensions.Hosting;
17+
using Services;
1818

1919
public class Startup
2020
{
2121
public Startup(IConfiguration configuration)
2222
=> this.Configuration = configuration;
2323

2424
public IConfiguration Configuration { get; }
25-
25+
2626
public void ConfigureServices(IServiceCollection services)
2727
{
2828
services
@@ -67,7 +67,7 @@ public void ConfigureServices(IServiceCollection services)
6767

6868
services.AddRazorPages();
6969
}
70-
70+
7171
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
7272
{
7373
if (env.IsDevelopment())

src/MyTested.AspNetCore.Mvc.Abstractions/Utilities/Extensions/ActionTestContextExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace MyTested.AspNetCore.Mvc.Utilities.Extensions
22
{
33
using System;
4+
using System.Threading.Tasks;
45
using Internal.TestContexts;
56
using Microsoft.AspNetCore.Mvc;
67

@@ -13,7 +14,8 @@ public static ActionTestContext ConvertMethodResult(this ActionTestContext testC
1314
{
1415
var methodReturnType = testContext.Method.ReturnType;
1516

16-
if (Reflection.AreAssignableByGeneric(ActionResultGenericType, methodReturnType))
17+
if (Reflection.AreAssignableByGeneric(ActionResultGenericType, methodReturnType)
18+
|| Reflection.AreAssignableByTaskGeneric(ActionResultGenericType, methodReturnType))
1719
{
1820
var methodResultType = testContext.MethodResult.GetType();
1921

src/MyTested.AspNetCore.Mvc.Abstractions/Utilities/Reflection.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Linq.Expressions;
99
using System.Reflection;
1010
using System.Runtime.CompilerServices;
11+
using System.Threading.Tasks;
1112
using Extensions;
1213
using Internal;
1314
using Microsoft.AspNetCore.Routing;
@@ -122,6 +123,24 @@ public static bool AreAssignableByGeneric(Type baseType, Type inheritedType)
122123
&& IsGeneric(baseType)
123124
&& baseType.IsAssignableFrom(inheritedType.GetGenericTypeDefinition());
124125

126+
/// <summary>
127+
/// Checks whether two types are assignable by generic task definition.
128+
/// </summary>
129+
/// <param name="baseTaskType">Base type to be checked.</param>
130+
/// <param name="inheritedTaskType">Inherited type to be checked.</param>
131+
/// <returns>True or false.</returns>
132+
public static bool AreAssignableByTaskGeneric(Type baseTaskType, Type inheritedTaskType)
133+
{
134+
if (!AreAssignableByGeneric(typeof(Task<>), inheritedTaskType))
135+
{
136+
return false;
137+
}
138+
139+
var inheritedGenericArgument = inheritedTaskType.GetGenericArguments().First();
140+
141+
return AreAssignableByGeneric(baseTaskType, inheritedGenericArgument);
142+
}
143+
125144
/// <summary>
126145
/// Checks whether two generic types have different generic arguments.
127146
/// </summary>

src/MyTested.AspNetCore.Mvc.Abstractions/Utilities/Validators/InvocationResultValidator.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public static void ValidateInvocationResultTypes(
5252
ComponentTestContext testContext,
5353
bool canBeAssignable = false,
5454
bool allowDifferentGenericTypeDefinitions = false,
55+
Type typeOfActualReturnValue = null,
5556
params Type[] typesOfExpectedReturnValue)
5657
{
5758
var invalid = false;
@@ -62,7 +63,8 @@ public static void ValidateInvocationResultTypes(
6263
testContext,
6364
type,
6465
canBeAssignable,
65-
allowDifferentGenericTypeDefinitions);
66+
allowDifferentGenericTypeDefinitions,
67+
typeOfActualReturnValue);
6668

6769
if (!invalid)
6870
{
@@ -76,7 +78,8 @@ public static void ValidateInvocationResultTypes(
7678
" or ",
7779
typesOfExpectedReturnValue.Select(t => t.ToFriendlyTypeName()));
7880

79-
var actualTypeName = testContext.MethodResult?.GetType().ToFriendlyTypeName();
81+
var actualTypeName = typeOfActualReturnValue?.ToFriendlyTypeName()
82+
?? testContext.MethodResult?.GetType().ToFriendlyTypeName();
8083

8184
ThrowNewInvocationResultAssertionException(
8285
testContext,

src/MyTested.AspNetCore.Mvc.Controllers/Builders/ActionResults/ActionResult/ActionResultOfTTestBuilder.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ public class ActionResultOfTTestBuilder<TResult>
2020
/// <see cref="ControllerTestContext"/> containing data about the currently executed assertion chain.
2121
/// </param>
2222
public ActionResultOfTTestBuilder(ControllerTestContext testContext)
23-
: base(testContext)
24-
{
25-
testContext.ConvertMethodResult();
26-
}
23+
: base(testContext)
24+
=> testContext.ConvertMethodResult();
2725

2826
/// <inheritdoc />
2927
public IActionResultOfTTestBuilder<TResult> AndAlso() => this;

src/MyTested.AspNetCore.Mvc.Controllers/Builders/Actions/ShouldReturn/ShouldReturnActionResultTestBuilder.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace MyTested.AspNetCore.Mvc.Builders.Actions.ShouldReturn
22
{
33
using System;
4+
using System.Threading.Tasks;
45
using ActionResults.ActionResult;
56
using And;
67
using Contracts.ActionResults.ActionResult;
@@ -84,8 +85,13 @@ private void ValidateActionResults()
8485
typesOfExpectedReturnValue: new[] { ActionResultType, GenericActionResultType });
8586

8687
private void ValidateActionResult<TResult>()
87-
=> InvocationResultValidator.ValidateInvocationResultType<ActionResult<TResult>>(
88+
=> InvocationResultValidator.ValidateInvocationResultTypes(
8889
this.TestContext,
89-
typeOfActualReturnValue: this.TestContext.Method.ReturnType);
90+
typeOfActualReturnValue: this.TestContext.Method.ReturnType,
91+
typesOfExpectedReturnValue: new[]
92+
{
93+
typeof(ActionResult<TResult>),
94+
typeof(Task<ActionResult<TResult>>)
95+
});
9096
}
9197
}

test/MyTested.AspNetCore.Mvc.Controllers.ActionResults.Test/BuildersTests/ActionResultsTests/ActionResultTests/ActionResultOfTTestBuilderTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,40 @@ public void ShouldReturnActionResultOfTWithDetailsShouldThrowExceptionWithIncorr
4242
},
4343
"When calling ActionResultOfT action in MvcController expected the response model to be the given model, but in fact it was a different one. Difference occurs at 'ResponseModel.IntegerValue'. Expected a value of '2', but in fact it was '1'.");
4444
}
45+
46+
[Fact]
47+
public void ShouldReturnActionResultOfAsyncTWithDetailsShouldNotThrowExceptionWithEqualResult()
48+
{
49+
MyController<MvcController>
50+
.Instance()
51+
.Calling(c => c.ActionResultOfTAsync(1))
52+
.ShouldReturn()
53+
.ActionResult<ResponseModel>(result => result
54+
.EqualTo(new ResponseModel
55+
{
56+
IntegerValue = 1,
57+
StringValue = "Test"
58+
}));
59+
}
60+
61+
[Fact]
62+
public void ShouldReturnActionResultOfTAsyncWithDetailsShouldThrowExceptionWithIncorrectResult()
63+
{
64+
Test.AssertException<ResponseModelAssertionException>(
65+
() =>
66+
{
67+
MyController<MvcController>
68+
.Instance()
69+
.Calling(c => c.ActionResultOfTAsync(1))
70+
.ShouldReturn()
71+
.ActionResult<ResponseModel>(result => result
72+
.EqualTo(new ResponseModel
73+
{
74+
IntegerValue = 2,
75+
StringValue = "Test"
76+
}));
77+
},
78+
"When calling ActionResultOfTAsync action in MvcController expected the response model to be the given model, but in fact it was a different one. Difference occurs at 'ResponseModel.IntegerValue'. Expected a value of '2', but in fact it was '1'.");
79+
}
4580
}
4681
}

0 commit comments

Comments
 (0)