Skip to content

Commit 11ade55

Browse files
committed
Controllers now can be created with inner builder (#318)
1 parent 16d4366 commit 11ade55

File tree

13 files changed

+226
-107
lines changed

13 files changed

+226
-107
lines changed

samples/Blog/Blog.Test/Controllers/ArticlesControllerTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public class ArticlesControllerTest
2020
[InlineData(18, 2, 6)]
2121
public void AllShouldReturnDefaultViewWithCorrectModel(int total, int page, int expectedCount)
2222
=> MyController<ArticlesController>
23-
.Instance()
24-
.WithData(ArticleTestData.GetArticles(total))
23+
.Instance(instance => instance
24+
.WithData(ArticleTestData.GetArticles(total)))
2525
.Calling(c => c.All(page))
2626
.ShouldReturn()
2727
.View(view => view
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
namespace MyTested.AspNetCore.Mvc.Builders.Contracts.Controllers
22
{
33
/// <summary>
4-
/// Used for adding AndAlso() method to the controller builder.
4+
/// Used for adding AndAlso() method to the controller instance builder.
55
/// </summary>
66
/// <typeparam name="TController">Class representing ASP.NET Core MVC controller.</typeparam>
7-
public interface IAndControllerInstanceBuilder<TController> : IControllerBuilder<TController>
7+
public interface IAndControllerInstanceBuilder<TController> : IControllerInstanceBuilder<TController>
88
where TController : class
99
{
1010
/// <summary>
1111
/// AndAlso method for better readability when building controller instance.
1212
/// </summary>
1313
/// <returns>The same <see cref="IAndControllerBuilder{TController}"/>.</returns>
14-
IAndControllerBuilder<TController> AndAlso();
14+
IAndControllerInstanceBuilder<TController> AndAlso();
1515
}
1616
}

src/MyTested.AspNetCore.Mvc.Controllers/Builders/Contracts/Controllers/IBaseControllerBuilder.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,47 @@
55
using Microsoft.AspNetCore.Mvc;
66

77
/// <summary>
8-
/// Used for building the controller which will be tested.
8+
/// Base controller builder.
99
/// </summary>
1010
/// <typeparam name="TController">Class representing ASP.NET Core MVC controller.</typeparam>
11-
/// <typeparam name="TBuilder">Class representing ASP.NET Core MVC test builder.</typeparam>
12-
public interface IBaseControllerBuilder<TController, TBuilder> : IBaseTestBuilderWithComponentBuilder<IAndControllerBuilder<TController>>
11+
/// <typeparam name="TBuilder">Base builder.</typeparam>
12+
public interface IBaseControllerBuilder<TController, TBuilder> : IBaseTestBuilderWithComponentBuilder<TBuilder>
1313
where TController : class
14+
where TBuilder : IBaseTestBuilder
1415
{
1516
/// <summary>
1617
/// Sets the <see cref="ControllerContext"/> on the tested controller.
1718
/// </summary>
1819
/// <param name="controllerContext">Instance of <see cref="ControllerContext"/> to set.</param>
1920
/// <returns>The same <see cref="IControllerBuilder{TController}"/>.</returns>
20-
IAndControllerBuilder<TController> WithControllerContext(ControllerContext controllerContext);
21+
TBuilder WithControllerContext(ControllerContext controllerContext);
2122

2223
/// <summary>
2324
/// Sets the <see cref="ControllerContext"/> on the tested controller.
2425
/// </summary>
2526
/// <param name="controllerContextSetup">Action setting the <see cref="ControllerContext"/>.</param>
2627
/// <returns>The same <see cref="IControllerBuilder{TController}"/>.</returns>
27-
IAndControllerBuilder<TController> WithControllerContext(Action<ControllerContext> controllerContextSetup);
28+
TBuilder WithControllerContext(Action<ControllerContext> controllerContextSetup);
2829

2930
/// <summary>
3031
/// Sets the <see cref="ActionContext"/> on the tested controller.
3132
/// </summary>
3233
/// <param name="actionContext">Instance of <see cref="ActionContext"/> to set.</param>
3334
/// <returns>The same <see cref="IControllerBuilder{TController}"/>.</returns>
34-
IAndControllerBuilder<TController> WithActionContext(ActionContext actionContext);
35+
TBuilder WithActionContext(ActionContext actionContext);
3536

3637
/// <summary>
3738
/// Sets the <see cref="ActionContext"/> on the tested controller.
3839
/// </summary>
3940
/// <param name="actionContextSetup">Action setting the <see cref="ActionContext"/>.</param>
4041
/// <returns>The same <see cref="IControllerBuilder{TController}"/>.</returns>
41-
IAndControllerBuilder<TController> WithActionContext(Action<ActionContext> actionContextSetup);
42+
TBuilder WithActionContext(Action<ActionContext> actionContextSetup);
4243

4344
/// <summary>
4445
/// Sets custom properties to the controller using a delegate.
4546
/// </summary>
4647
/// <param name="controllerSetup">Action to use for controller setup.</param>
4748
/// <returns>The same <see cref="IControllerBuilder{TController}"/>.</returns>
48-
IAndControllerBuilder<TController> WithSetup(Action<TController> controllerSetup);
49+
TBuilder WithSetup(Action<TController> controllerSetup);
4950
}
5051
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
namespace MyTested.AspNetCore.Mvc.Builders.Contracts.Controllers
2+
{
3+
using System;
4+
using System.Linq.Expressions;
5+
using System.Threading.Tasks;
6+
using Actions;
7+
using Base;
8+
9+
/// <summary>
10+
/// Used for testing the controller.
11+
/// </summary>
12+
/// <typeparam name="TController">Class representing ASP.NET Core MVC controller.</typeparam>
13+
public interface IControllerActionCallBuilder<TController> : IBaseTestBuilderWithComponent
14+
{
15+
/// <summary>
16+
/// Used for testing controller additional details.
17+
/// </summary>
18+
/// <returns>Test builder of <see cref="IControllerTestBuilder"/> type.</returns>
19+
IControllerTestBuilder ShouldHave();
20+
21+
/// <summary>
22+
/// Indicates which action should be invoked and tested.
23+
/// </summary>
24+
/// <typeparam name="TActionResult">Type of result from action.</typeparam>
25+
/// <param name="actionCall">Method call expression indicating invoked action.</param>
26+
/// <returns>Test builder of <see cref="IActionResultTestBuilder{TActionResult}"/> type.</returns>
27+
IActionResultTestBuilder<TActionResult> Calling<TActionResult>(Expression<Func<TController, TActionResult>> actionCall);
28+
29+
/// <summary>
30+
/// Indicates which action should be invoked and tested.
31+
/// </summary>
32+
/// <typeparam name="TActionResult">Type of result from action.</typeparam>
33+
/// <param name="actionCall">Method call expression indicating invoked asynchronous action.</param>
34+
/// <returns>Test builder of <see cref="IActionResultTestBuilder{TActionResult}"/> type.</returns>
35+
IActionResultTestBuilder<TActionResult> Calling<TActionResult>(Expression<Func<TController, Task<TActionResult>>> actionCall);
36+
37+
/// <summary>
38+
/// Indicates which action should be invoked and tested.
39+
/// </summary>
40+
/// <param name="actionCall">Method call expression indicating invoked void action.</param>
41+
/// <returns>Test builder of <see cref="IActionResultTestBuilder{TActionResult}"/> type.</returns>
42+
IVoidActionResultTestBuilder Calling(Expression<Action<TController>> actionCall);
43+
44+
/// <summary>
45+
/// Indicates which action should be invoked and tested.
46+
/// </summary>
47+
/// <param name="actionCall">Method call expression indicating invoked asynchronous void action.</param>
48+
/// <returns>Test builder of <see cref="IActionResultTestBuilder{TActionResult}"/> type.</returns>
49+
IVoidActionResultTestBuilder Calling(Expression<Func<TController, Task>> actionCall);
50+
}
51+
}
Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,13 @@
11
namespace MyTested.AspNetCore.Mvc.Builders.Contracts.Controllers
22
{
3-
using System;
4-
using System.Linq.Expressions;
5-
using System.Threading.Tasks;
6-
using Actions;
7-
83
/// <summary>
94
/// Used for building the controller which will be tested.
105
/// </summary>
116
/// <typeparam name="TController">Class representing ASP.NET Core MVC controller.</typeparam>
12-
public interface IControllerBuilder<TController> : IBaseControllerBuilder<TController, IAndControllerBuilder<TController>>
7+
public interface IControllerBuilder<TController>
8+
: IBaseControllerBuilder<TController, IAndControllerBuilder<TController>>,
9+
IControllerActionCallBuilder<TController>
1310
where TController : class
1411
{
15-
/// <summary>
16-
/// Used for testing controller additional details.
17-
/// </summary>
18-
/// <returns>Test builder of <see cref="IControllerTestBuilder"/> type.</returns>
19-
IControllerTestBuilder ShouldHave();
20-
21-
/// <summary>
22-
/// Indicates which action should be invoked and tested.
23-
/// </summary>
24-
/// <typeparam name="TActionResult">Type of result from action.</typeparam>
25-
/// <param name="actionCall">Method call expression indicating invoked action.</param>
26-
/// <returns>Test builder of <see cref="IActionResultTestBuilder{TActionResult}"/> type.</returns>
27-
IActionResultTestBuilder<TActionResult> Calling<TActionResult>(Expression<Func<TController, TActionResult>> actionCall);
28-
29-
/// <summary>
30-
/// Indicates which action should be invoked and tested.
31-
/// </summary>
32-
/// <typeparam name="TActionResult">Type of result from action.</typeparam>
33-
/// <param name="actionCall">Method call expression indicating invoked asynchronous action.</param>
34-
/// <returns>Test builder of <see cref="IActionResultTestBuilder{TActionResult}"/> type.</returns>
35-
IActionResultTestBuilder<TActionResult> Calling<TActionResult>(Expression<Func<TController, Task<TActionResult>>> actionCall);
36-
37-
/// <summary>
38-
/// Indicates which action should be invoked and tested.
39-
/// </summary>
40-
/// <param name="actionCall">Method call expression indicating invoked void action.</param>
41-
/// <returns>Test builder of <see cref="IActionResultTestBuilder{TActionResult}"/> type.</returns>
42-
IVoidActionResultTestBuilder Calling(Expression<Action<TController>> actionCall);
43-
44-
/// <summary>
45-
/// Indicates which action should be invoked and tested.
46-
/// </summary>
47-
/// <param name="actionCall">Method call expression indicating invoked asynchronous void action.</param>
48-
/// <returns>Test builder of <see cref="IActionResultTestBuilder{TActionResult}"/> type.</returns>
49-
IVoidActionResultTestBuilder Calling(Expression<Func<TController, Task>> actionCall);
5012
}
5113
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
namespace MyTested.AspNetCore.Mvc.Builders.Controllers
2+
{
3+
using Components;
4+
using Contracts.Base;
5+
using Internal.Contracts;
6+
using Internal.TestContexts;
7+
using Microsoft.AspNetCore.Mvc.Controllers;
8+
using Microsoft.AspNetCore.Mvc.Internal;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using System.Linq.Expressions;
11+
using System.Reflection;
12+
using Utilities.Extensions;
13+
14+
/// <summary>
15+
/// Base controller builder.
16+
/// </summary>
17+
/// /// <typeparam name="TController">Class representing ASP.NET Core MVC controller.</typeparam>
18+
/// <typeparam name="TBuilder">Base builder.</typeparam>
19+
public abstract partial class BaseControllerBuilder<TController, TBuilder>
20+
: BaseComponentBuilder<TController, ControllerTestContext, TBuilder>
21+
where TController : class
22+
where TBuilder : IBaseTestBuilder
23+
{
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="BaseControllerBuilder{TController, TBuilder}"/> class.
26+
/// </summary>
27+
/// <param name="testContext"><see cref="ControllerTestContext"/> containing data about the currently executed assertion chain.</param>
28+
protected BaseControllerBuilder(ControllerTestContext testContext)
29+
: base(testContext)
30+
{
31+
}
32+
33+
protected override string ComponentName => "controller";
34+
35+
protected override bool IsValidComponent
36+
=> this.Services
37+
.GetRequiredService<IValidControllersCache>()
38+
.IsValid(typeof(TController));
39+
40+
protected override TController TryCreateComponentWithFactory()
41+
{
42+
try
43+
{
44+
return this.Services
45+
.GetService<IControllerFactory>()
46+
?.CreateController(this.TestContext.ComponentContext) as TController;
47+
}
48+
catch
49+
{
50+
return null;
51+
}
52+
}
53+
54+
protected override void ActivateComponent()
55+
=> this.Services
56+
.GetServices<IControllerPropertyActivator>()
57+
?.ForEach(a => a.Activate(this.TestContext.ComponentContext, this.TestContext.Component));
58+
59+
protected override void ProcessAndValidateMethod(LambdaExpression methodCall, MethodInfo methodInfo)
60+
{
61+
// Intentionally left empty. Not all controller builders allow action execution.
62+
}
63+
}
64+
}

src/MyTested.AspNetCore.Mvc.Controllers/Builders/Controllers/ControllerSetupBuilder.cs renamed to src/MyTested.AspNetCore.Mvc.Controllers/Builders/Controllers/BaseControllerSetupBuilder.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,39 @@
22
{
33
using System;
44
using System.Reflection;
5-
using Contracts.Controllers;
65
using Internal.Controllers;
76
using Microsoft.AspNetCore.Mvc;
87
using Utilities.Validators;
98

109
/// <content>
1110
/// Used for building the controller which will be tested.
1211
/// </content>
13-
public partial class ControllerBuilder<TController>
12+
public abstract partial class BaseControllerBuilder<TController, TBuilder>
1413
{
1514
/// <inheritdoc />
16-
public IAndControllerBuilder<TController> WithControllerContext(ControllerContext controllerContext)
17-
{
18-
return this.WithActionContext(controllerContext);
19-
}
15+
public TBuilder WithControllerContext(ControllerContext controllerContext)
16+
=> this.WithActionContext(controllerContext);
2017

2118
/// <inheritdoc />
22-
public IAndControllerBuilder<TController> WithControllerContext(Action<ControllerContext> controllerContextSetup)
19+
public TBuilder WithControllerContext(Action<ControllerContext> controllerContextSetup)
2320
{
2421
this.TestContext.ComponentContextPreparationDelegate += controllerContextSetup;
25-
return this;
22+
return this.Builder;
2623
}
2724

2825
/// <inheritdoc />
29-
public IAndControllerBuilder<TController> WithActionContext(ActionContext actionContext)
26+
public TBuilder WithActionContext(ActionContext actionContext)
3027
{
3128
CommonValidator.CheckForNullReference(actionContext, nameof(ActionContext));
3229
this.TestContext.ComponentContext = ControllerContextMock.FromActionContext(this.TestContext, actionContext);
33-
return this;
30+
return this.Builder;
3431
}
3532

3633
/// <inheritdoc />
37-
public IAndControllerBuilder<TController> WithActionContext(Action<ActionContext> actionContextSetup)
34+
public TBuilder WithActionContext(Action<ActionContext> actionContextSetup)
3835
{
3936
this.TestContext.ComponentContextPreparationDelegate += actionContextSetup;
40-
return this;
37+
return this.Builder;
4138
}
4239

4340
protected override void PrepareComponentContext()
Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
namespace MyTested.AspNetCore.Mvc.Builders.Controllers
22
{
3-
using Components;
43
using Contracts.Controllers;
54
using Internal.Configuration;
6-
using Internal.Contracts;
75
using Internal.TestContexts;
8-
using Microsoft.AspNetCore.Mvc.Controllers;
9-
using Microsoft.AspNetCore.Mvc.Internal;
10-
using Microsoft.Extensions.DependencyInjection;
11-
using Utilities.Extensions;
126

137
/// <summary>
148
/// Used for building the controller which will be tested.
159
/// </summary>
1610
/// <typeparam name="TController">Class representing ASP.NET Core MVC controller.</typeparam>
17-
public partial class ControllerBuilder<TController> : BaseComponentBuilder<TController, ControllerTestContext, IAndControllerBuilder<TController>>, IAndControllerBuilder<TController>
11+
public partial class ControllerBuilder<TController>
12+
: BaseControllerBuilder<TController, IAndControllerBuilder<TController>>,
13+
IAndControllerBuilder<TController>
1814
where TController : class
1915
{
2016
/// <summary>
@@ -30,13 +26,6 @@ public ControllerBuilder(ControllerTestContext testContext)
3026

3127
public bool EnabledModelStateValidation { get; set; }
3228

33-
protected override string ComponentName => "controller";
34-
35-
protected override bool IsValidComponent
36-
=> this.Services
37-
.GetRequiredService<IValidControllersCache>()
38-
.IsValid(typeof(TController));
39-
4029
/// <inheritdoc />
4130
public IAndControllerBuilder<TController> AndAlso() => this;
4231

@@ -48,24 +37,5 @@ public IControllerTestBuilder ShouldHave()
4837
}
4938

5039
protected override IAndControllerBuilder<TController> SetBuilder() => this;
51-
52-
protected override TController TryCreateComponentWithFactory()
53-
{
54-
try
55-
{
56-
return this.Services
57-
.GetService<IControllerFactory>()
58-
?.CreateController(this.TestContext.ComponentContext) as TController;
59-
}
60-
catch
61-
{
62-
return null;
63-
}
64-
}
65-
66-
protected override void ActivateComponent()
67-
=> this.Services
68-
.GetServices<IControllerPropertyActivator>()
69-
?.ForEach(a => a.Activate(this.TestContext.ComponentContext, this.TestContext.Component));
7040
}
7141
}

0 commit comments

Comments
 (0)