Skip to content

Commit a62ad3c

Browse files
authored
Merge pull request #329 - Added WithModelState Builder
Added WithModelState Builder
2 parents b620d86 + f5d5818 commit a62ad3c

File tree

5 files changed

+193
-0
lines changed

5 files changed

+193
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace MyTested.AspNetCore.Mvc.Builders.Contracts.Models
2+
{
3+
/// <summary>
4+
/// Used for adding AndAlso() method to the <see cref="Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary"/> builder.
5+
/// </summary>
6+
public interface IAndModelStateBuilder : IModelStateBuilder
7+
{
8+
/// <summary>
9+
/// AndAlso method for better readability when building <see cref="Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary"/>.
10+
/// </summary>
11+
/// <returns>The same <see cref="IModelStateBuilder"/>.</returns>
12+
IModelStateBuilder AndAlso();
13+
}
14+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
namespace MyTested.AspNetCore.Mvc.Builders.Contracts.Models
2+
{
3+
using System.Collections.Generic;
4+
5+
/// <summary>
6+
/// Used for building <see cref="Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary"/>.
7+
/// </summary>
8+
public interface IModelStateBuilder
9+
{
10+
/// <summary>
11+
/// Adds an error to the built <see cref="Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary"/>
12+
/// </summary>
13+
/// <param name="key">Key to set as string.</param>
14+
/// <param name="errorMessage">Error message to set as string.</param>
15+
/// <returns></returns>
16+
IAndModelStateBuilder WithError(string key, string errorMessage);
17+
18+
/// <summary>
19+
/// Adds model state entries to the built <see cref="Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary"/>
20+
/// </summary>
21+
/// <param name="errors">Model state entries as dictionary.</param>
22+
/// <returns></returns>
23+
IAndModelStateBuilder WithErrors(IDictionary<string, string> errors);
24+
25+
/// <summary>
26+
/// Adds model state entries to the built <see cref="Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary"/>
27+
/// </summary>
28+
/// <param name="errors">Model state entries as anonymous object.</param>
29+
/// <returns></returns>
30+
IAndModelStateBuilder WithErrors(object errors);
31+
}
32+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
namespace MyTested.AspNetCore.Mvc.Builders.Models
2+
{
3+
using System.Collections.Generic;
4+
using Microsoft.AspNetCore.Mvc.ModelBinding;
5+
using Microsoft.AspNetCore.Routing;
6+
using Contracts.Models;
7+
using Internal.TestContexts;
8+
using Utilities.Extensions;
9+
10+
/// <summary>
11+
/// Used for building <see cref="ModelStateDictionary"/>
12+
/// </summary>
13+
public class ModelStateBuilder : IAndModelStateBuilder
14+
{
15+
/// <summary>
16+
/// Initializes a new instance of the <see cref="ModelStateBuilder"/> class.
17+
/// </summary>
18+
/// <param name="actionContext"><see cref="ModelStateDictionary"/> to build.</param>
19+
public ModelStateBuilder(ActionTestContext actionContext)
20+
=> this.ModelState = actionContext.ModelState;
21+
22+
/// <summary>
23+
/// Gets the <see cref="ModelStateDictionary"/>
24+
/// </summary>
25+
/// <value>The built <see cref="ModelStateDictionary"/></value>
26+
protected ModelStateDictionary ModelState { get; set; }
27+
28+
/// <inheritdoc />
29+
public IAndModelStateBuilder WithError(string key, string errorMessage)
30+
{
31+
this.AddError(key, errorMessage);
32+
return this;
33+
}
34+
35+
/// <inheritdoc />
36+
public IAndModelStateBuilder WithErrors(IDictionary<string, string> errors)
37+
{
38+
errors.ForEach(err => this.AddError(err.Key, err.Value));
39+
return this;
40+
}
41+
42+
/// <inheritdoc />
43+
public IAndModelStateBuilder WithErrors(object errors)
44+
{
45+
var errorsAsDictionary = new RouteValueDictionary(errors);
46+
errorsAsDictionary
47+
.ForEach(err => this.AddError(err.Key, err.Value.ToString()));
48+
49+
return this;
50+
}
51+
52+
/// <inheritdoc />
53+
public IModelStateBuilder AndAlso() => this;
54+
55+
private void AddError(string key, string errorMessage)
56+
=> this.ModelState.AddModelError(key, errorMessage);
57+
}
58+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace MyTested.AspNetCore.Mvc
2+
{
3+
using System;
4+
using Builders.Base;
5+
using Builders.Contracts.Base;
6+
using Builders.Contracts.Models;
7+
using Builders.Models;
8+
using Internal.TestContexts;
9+
10+
/// <summary>
11+
/// Contains extension methods for <see cref="IBaseTestBuilderWithComponentBuilder{TBuilder}"/>.
12+
/// </summary>
13+
public static class ComponentBuilderModelStateExtensions
14+
{
15+
public static TBuilder WithModelState<TBuilder>(
16+
this IBaseTestBuilderWithComponentBuilder<TBuilder> builder,
17+
Action<IModelStateBuilder> modelStateTestBuilder)
18+
where TBuilder : IBaseTestBuilder
19+
{
20+
var actualBuilder = (BaseTestBuilderWithComponentBuilder<TBuilder>)builder;
21+
22+
modelStateTestBuilder(new ModelStateBuilder(actualBuilder.TestContext as ActionTestContext));
23+
24+
return actualBuilder.Builder;
25+
}
26+
}
27+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
namespace MyTested.AspNetCore.Mvc.Test.BuildersTests.ModelsTests
2+
{
3+
using Setups;
4+
using Setups.Controllers;
5+
using Xunit;
6+
using System.Collections.Generic;
7+
8+
public class ModelStateBuilderTests
9+
{
10+
[Fact]
11+
public void WithModelStateWithErrorShouldWorkCorrectly()
12+
{
13+
var requestBody = TestObjectFactory.GetValidRequestModel();
14+
15+
MyController<MvcController>
16+
.Instance()
17+
.WithModelState(modelState => modelState
18+
.WithError("TestError", "Invalid value"))
19+
.Calling(c => c.BadRequestWithModelState(requestBody))
20+
.ShouldReturn()
21+
.BadRequest();
22+
}
23+
24+
[Fact]
25+
public void WithModelStateWithErrorsDictionaryShouldWorkCorrectly()
26+
{
27+
var requestBody = TestObjectFactory.GetValidRequestModel();
28+
var errorsDictionary = new Dictionary<string, string>()
29+
{
30+
["First"] = "SomeError",
31+
["Second"] = "AnotherError",
32+
};
33+
34+
MyController<MvcController>
35+
.Instance()
36+
.WithModelState(modelState => modelState
37+
.WithErrors(errorsDictionary))
38+
.Calling(c => c.BadRequestWithModelState(requestBody))
39+
.ShouldReturn()
40+
.BadRequest();
41+
}
42+
43+
[Fact]
44+
public void WithModelStateWithErrorsObjectShouldWorkCorrectly()
45+
{
46+
var requestBody = TestObjectFactory.GetValidRequestModel();
47+
var errorsObjcet = new
48+
{
49+
First = "SomeError",
50+
Second = "AnotherError",
51+
};
52+
53+
MyController<MvcController>
54+
.Instance()
55+
.WithModelState(modelState => modelState
56+
.WithErrors(errorsObjcet))
57+
.Calling(c => c.BadRequestWithModelState(requestBody))
58+
.ShouldReturn()
59+
.BadRequest();
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)