Skip to content

Commit 1758490

Browse files
committed
Added simple And method for better readability and updated README.md
1 parent a96ea88 commit 1758490

File tree

7 files changed

+88
-5
lines changed

7 files changed

+88
-5
lines changed

MyWebApi.Tests/BuildersTests/ResponseModelsTests/ResponseModelErrorDetailsTestBuilderTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ public void ThatEqualsShouldNotThrowExceptionWhenProvidedMessageIsValid()
1919
.ShouldHaveModelStateFor<RequestModel>()
2020
.ContainingNoModelStateErrorFor(m => m.NonRequiredString)
2121
.ContainingModelStateErrorFor(m => m.RequiredString).ThatEquals("The RequiredString field is required.")
22+
.And()
2223
.ContainingModelStateErrorFor(m => m.RequiredString)
24+
.And()
2325
.ContainingNoModelStateErrorFor(m => m.NotValidateInteger)
26+
.And()
2427
.ContainingModelStateError("RequiredString")
2528
.ContainingModelStateErrorFor(m => m.Integer).ThatEquals(string.Format("The field Integer must be between {0} and {1}.", 1, int.MaxValue))
2629
.ContainingModelStateError("RequiredString")
@@ -41,6 +44,7 @@ public void ThatEqualsShouldThrowExceptionWhenProvidedMessageIsValid()
4144
.Calling(c => c.ModelStateCheck(requestModelWithErrors))
4245
.ShouldHaveModelStateFor<RequestModel>()
4346
.ContainingNoModelStateErrorFor(m => m.NonRequiredString)
47+
.And()
4448
.ContainingModelStateErrorFor(m => m.RequiredString).ThatEquals("RequiredString field is required.")
4549
.ContainingModelStateErrorFor(m => m.Integer).ThatEquals(string.Format("Integer must be between {0} and {1}.", 1, int.MaxValue));
4650
}

MyWebApi/Builders/Actions/ShouldHaveModelState.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@ public partial class ActionResultTestBuilder<TActionResult>
1818
/// <returns>Response model test builder.</returns>
1919
public IResponseModelErrorTestBuilder<TRequestModel> ShouldHaveModelStateFor<TRequestModel>()
2020
{
21-
return new ResponseModelErrorTestBuilder<TRequestModel>(Controller, ActionName);
21+
return new ResponseModelErrorTestBuilder<TRequestModel>(this.Controller, this.ActionName);
2222
}
2323

2424
/// <summary>
2525
/// Checks whether the tested action's provided model state is valid.
2626
/// </summary>
2727
public void ShouldHaveValidModelState()
2828
{
29-
CheckValidModelState();
29+
this.CheckValidModelState();
3030
}
3131

3232
/// <summary>
3333
/// Checks whether the tested action's provided model state is not valid.
3434
/// </summary>
3535
public void ShouldHaveInvalidModelState()
3636
{
37-
if (Controller.ModelState.Count == 0)
37+
if (this.Controller.ModelState.Count == 0)
3838
{
3939
throw new ResponseModelErrorAssertionException(string.Format(
4040
"When calling {0} action in {1} expected to have invalid model state, but was in fact valid.",

MyWebApi/Builders/Contracts/IResponseModelErrorDetailsTestBuilder.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,11 @@ IResponseModelErrorDetailsTestBuilder<TResponseModel> ContainingModelStateErrorF
6161
/// <returns>Response model error details test builder.</returns>
6262
IResponseModelErrorTestBuilder<TResponseModel> ContainingNoModelStateErrorFor<TMember>(
6363
Expression<Func<TResponseModel, TMember>> memberWithNoError);
64+
65+
/// <summary>
66+
/// And method for better readability when chaining error message tests.
67+
/// </summary>
68+
/// <returns>Response model error details test builder.</returns>
69+
IResponseModelErrorTestBuilder<TResponseModel> And();
6470
}
6571
}

MyWebApi/Builders/Contracts/IResponseModelErrorTestBuilder{TResponseModel}.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,11 @@ public interface IResponseModelErrorTestBuilder<TResponseModel> : IResponseModel
3232
/// <returns>This instance in order to support method chaining.</returns>
3333
IResponseModelErrorTestBuilder<TResponseModel> ContainingNoModelStateErrorFor<TMember>(
3434
Expression<Func<TResponseModel, TMember>> memberWithNoError);
35+
36+
/// <summary>
37+
/// And method for better readability when chaining error message tests.
38+
/// </summary>
39+
/// <returns>Response model error details test builder.</returns>
40+
IResponseModelErrorTestBuilder<TResponseModel> And();
3541
}
3642
}

MyWebApi/Builders/ResponseModels/ResponseModelErrorDetailsTestBuilder.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,15 @@ public IResponseModelErrorTestBuilder<TResponseModel> ContainingNoModelStateErro
143143
return this.responseModelErrorTestBuilder.ContainingNoModelStateErrorFor(memberWithNoError);
144144
}
145145

146+
/// <summary>
147+
/// And method for better readability when chaining error message tests.
148+
/// </summary>
149+
/// <returns>Response model error details test builder.</returns>
150+
public IResponseModelErrorTestBuilder<TResponseModel> And()
151+
{
152+
return this.responseModelErrorTestBuilder;
153+
}
154+
146155
private void ThrowNewResponseModelErrorAssertionException(string messageFormat, string operation)
147156
{
148157
throw new ResponseModelErrorAssertionException(string.Format(

MyWebApi/Builders/ResponseModels/ResponseModelErrorTestBuilder{TResponseModel}.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ public IResponseModelErrorTestBuilder<TResponseModel> ContainingNoModelStateErro
8484
return this;
8585
}
8686

87+
/// <summary>
88+
/// And method for better readability when chaining error message tests.
89+
/// </summary>
90+
/// <returns>Response model error details test builder.</returns>
91+
public IResponseModelErrorTestBuilder<TResponseModel> And()
92+
{
93+
return this;
94+
}
95+
8796
private void ThrowNewResponseModelErrorAssertionException(string messageFormat, string errorKey)
8897
{
8998
throw new ResponseModelErrorAssertionException(string.Format(

README.md

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ MyWebApi is unit testing framework providing easy fluent interface to test the A
99

1010
### Controller instantiation
1111

12-
You have a couple of options from which you can setup the controller you want to test. The framework gives you static `MyWebApi` class from which the test builder starts.
12+
You have a couple of options from which you can setup the controller you want to test. The framework gives you static `MyWebApi` class from which the test builder starts:
1313

1414
```c#
1515
// instantiates controller with parameterless constructor
@@ -23,7 +23,7 @@ MyWebApi
2323

2424
### Calling actions
2525

26-
You can call any action using lambda expression. All parameter values will be resolved and model state validation will be performed on them.
26+
You can call any action using lambda expression. All parameter values will be resolved and model state validation will be performed on them:
2727

2828
```c#
2929
// calls action with no parameters
@@ -42,6 +42,55 @@ MyWebApi
4242
.CallingAsync(c => c.SomeActionAsync());
4343
```
4444

45+
### Model state validation
46+
47+
You can test whether model state is valid/invalid or contains any specific error:
48+
49+
```c#
50+
// tests whether model state is valid
51+
MyWebApi
52+
.Controller<WebApiController>()
53+
.Calling(c => c.SomeAction(requestModel))
54+
.ShouldHaveValidModelState();
55+
56+
// tests whether model state is not valid
57+
MyWebApi
58+
.Controller<WebApiController>()
59+
.Calling(c => c.SomeAction(requestModel))
60+
.ShouldHaveInvalidModelState();
61+
62+
// tests whether model state error exists (or does not exist) for specific key (not recommended because of magic string)
63+
MyWebApi
64+
.Controller<WebApiController>()
65+
.Calling(c => c.SomeAction(requestModel))
66+
.ShouldHaveModelStateFor<RequestModel>()
67+
.ContainingModelStateError("propertyName")
68+
.And() // calling And method is not necessary but provides better readability
69+
.ContainingNoModelStateError("anotherPropertyName");
70+
71+
// tests whether model state error exists by using lambda expression
72+
MyWebApi
73+
.Controller<WebApiController>()
74+
.Calling(c => c.SomeAction(requestModel))
75+
.ShouldHaveModelStateFor<RequestModel>()
76+
.ContainingModelStateErrorFor(m => m.SomeProperty)
77+
.And()
78+
.ContainingNoModelStateErrorFor(m => m.AnotherProperty);
79+
80+
// tests the error message for specific property
81+
MyWebApi
82+
.Controller<WebApiController>()
83+
.Calling(c => c.SomeAction(requestModel))
84+
.ShouldHaveModelStateFor<RequestModel>()
85+
.ContainingModelStateErrorFor(m => m.SomeProperty).ThatEquals("Error message") // error message must be equal to the provided string
86+
.And()
87+
.ContainingModelStateErrorFor(m => m.SecondProperty).BeginningWith("Error") // error message must begin with the provided string
88+
.And()
89+
.ContainingModelStateErrorFor(m => m.ThirdProperty).EndingWith("message") // error message must end with the provided string
90+
.And()
91+
.ContainingModelStateErrorFor(m => m.SecondProperty).Containing("ror mes"); // error message must contain the provided string
92+
```
93+
4594
## Any questions, comments or additions?
4695

4796
Leave an issue on the [issues page](https://github.com/ivaylokenov/MyWebApi/issues) or send a [pull request](https://github.com/ivaylokenov/MyWebApi/pulls).

0 commit comments

Comments
 (0)