This commit is contained in:
Родитель
f52cc706e2
Коммит
9d460e6a19
183
readme.md
183
readme.md
|
@ -5,10 +5,10 @@ Source File: /readme.source.md
|
|||
To change this file edit the source file and then run MarkdownSnippets.
|
||||
-->
|
||||
|
||||
# <img src="/src/icon.png" height="30px"> Verify.Web
|
||||
# <img src="/src/icon.png" height="30px"> Verify.EntityFramework
|
||||
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/eedjhmx5o3082tyq?svg=true)](https://ci.appveyor.com/project/SimonCropp/verify-web)
|
||||
[![NuGet Status](https://img.shields.io/nuget/v/Verify.Web.svg)](https://www.nuget.org/packages/Verify.Web/)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/eedjhmx5o3082tyq?svg=true)](https://ci.appveyor.com/project/SimonCropp/verify-entityframework)
|
||||
[![NuGet Status](https://img.shields.io/nuget/v/Verify.EntityFramework.svg)](https://www.nuget.org/packages/Verify.EntityFramework/)
|
||||
|
||||
Extends [Verify](https://github.com/SimonCropp/Verify) to allow verification of web bits.
|
||||
|
||||
|
@ -17,13 +17,12 @@ Extends [Verify](https://github.com/SimonCropp/Verify) to allow verification of
|
|||
## Contents
|
||||
|
||||
* [Usage](#usage)
|
||||
* [Controller](#controller)
|
||||
* [Middleware](#middleware)<!-- endtoc -->
|
||||
* [Controller](#controller)<!-- endtoc -->
|
||||
|
||||
|
||||
## NuGet package
|
||||
|
||||
https://nuget.org/packages/Verify.Web/
|
||||
https://nuget.org/packages/Verify.EntityFramework/
|
||||
|
||||
|
||||
## Usage
|
||||
|
@ -33,7 +32,7 @@ Enable VerifyWeb once at assembly load time:
|
|||
<!-- snippet: Enable -->
|
||||
<a id='snippet-enable'/></a>
|
||||
```cs
|
||||
VerifyWeb.Enable();
|
||||
VerifyEntityFramework.Enable();
|
||||
```
|
||||
<sup><a href='/src/Tests/GlobalSetup.cs#L9-L11' title='File snippet `enable` was extracted from'>snippet source</a> | <a href='#snippet-enable' title='Navigate to start of snippet `enable`'>anchor</a></sup>
|
||||
<!-- endsnippet -->
|
||||
|
@ -43,182 +42,18 @@ VerifyWeb.Enable();
|
|||
|
||||
Given the following controller:
|
||||
|
||||
<!-- snippet: MyController.cs -->
|
||||
<a id='snippet-MyController.cs'/></a>
|
||||
```cs
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
public class MyController :
|
||||
Controller
|
||||
{
|
||||
public ActionResult<List<DataItem>> Method(string input)
|
||||
{
|
||||
var headers = HttpContext.Response.Headers;
|
||||
headers.Add("headerKey", "headerValue");
|
||||
headers.Add("receivedInput", input);
|
||||
|
||||
var cookies = HttpContext.Response.Cookies;
|
||||
cookies.Append("cookieKey", "cookieValue");
|
||||
|
||||
var items = new List<DataItem>
|
||||
{
|
||||
new DataItem("Value1"),
|
||||
new DataItem("Value2")
|
||||
};
|
||||
return new ActionResult<List<DataItem>>(items);
|
||||
}
|
||||
|
||||
public class DataItem
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public DataItem(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
<sup><a href='/src/Tests/Snippets/MyController.cs#L1-L33' title='File snippet `MyController.cs` was extracted from'>snippet source</a> | <a href='#snippet-MyController.cs' title='Navigate to start of snippet `MyController.cs`'>anchor</a></sup>
|
||||
<!-- endsnippet -->
|
||||
//snippet: MyController.cs
|
||||
|
||||
This test:
|
||||
|
||||
<!-- snippet: MyControllerTest -->
|
||||
<a id='snippet-mycontrollertest'/></a>
|
||||
```cs
|
||||
[Fact]
|
||||
public Task Test()
|
||||
{
|
||||
var context = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext()
|
||||
};
|
||||
var controller = new MyController
|
||||
{
|
||||
ControllerContext = context
|
||||
};
|
||||
|
||||
var result = controller.Method("inputValue");
|
||||
return Verify(
|
||||
new
|
||||
{
|
||||
result,
|
||||
context
|
||||
});
|
||||
}
|
||||
```
|
||||
<sup><a href='/src/Tests/Snippets/MyControllerTests.cs#L11-L32' title='File snippet `mycontrollertest` was extracted from'>snippet source</a> | <a href='#snippet-mycontrollertest' title='Navigate to start of snippet `mycontrollertest`'>anchor</a></sup>
|
||||
<!-- endsnippet -->
|
||||
//snippet: MyControllerTest
|
||||
|
||||
Will result in the following verified file:
|
||||
|
||||
<!-- snippet: MyControllerTests.Test.verified.txt -->
|
||||
<a id='snippet-MyControllerTests.Test.verified.txt'/></a>
|
||||
```txt
|
||||
{
|
||||
result: [
|
||||
{
|
||||
Value: 'Value1'
|
||||
},
|
||||
{
|
||||
Value: 'Value2'
|
||||
}
|
||||
],
|
||||
context: {
|
||||
Headers: {
|
||||
headerKey: 'headerValue',
|
||||
receivedInput: 'inputValue'
|
||||
},
|
||||
Cookies: {
|
||||
cookieKey: 'cookieValue'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
<sup><a href='/src/Tests/Snippets/MyControllerTests.Test.verified.txt#L1-L19' title='File snippet `MyControllerTests.Test.verified.txt` was extracted from'>snippet source</a> | <a href='#snippet-MyControllerTests.Test.verified.txt' title='Navigate to start of snippet `MyControllerTests.Test.verified.txt`'>anchor</a></sup>
|
||||
<!-- endsnippet -->
|
||||
//snippet: MyControllerTests.Test.verified.txt
|
||||
|
||||
|
||||
|
||||
### Middleware
|
||||
|
||||
Given the following middleware:
|
||||
|
||||
<!-- snippet: MyMiddleware.cs -->
|
||||
<a id='snippet-MyMiddleware.cs'/></a>
|
||||
```cs
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
public class MyMiddleware
|
||||
{
|
||||
RequestDelegate next;
|
||||
|
||||
public MyMiddleware(RequestDelegate next)
|
||||
{
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
context.Response.Headers.Add("headerKey", "headerValue");
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
```
|
||||
<sup><a href='/src/Tests/Snippets/MyMiddleware.cs#L1-L18' title='File snippet `MyMiddleware.cs` was extracted from'>snippet source</a> | <a href='#snippet-MyMiddleware.cs' title='Navigate to start of snippet `MyMiddleware.cs`'>anchor</a></sup>
|
||||
<!-- endsnippet -->
|
||||
|
||||
This test:
|
||||
|
||||
<!-- snippet: MyMiddlewareTest -->
|
||||
<a id='snippet-mymiddlewaretest'/></a>
|
||||
```cs
|
||||
[Fact]
|
||||
public async Task Test()
|
||||
{
|
||||
var nextCalled = false;
|
||||
var middleware = new MyMiddleware(
|
||||
_ =>
|
||||
{
|
||||
nextCalled = true;
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
await middleware.Invoke(context);
|
||||
|
||||
await Verify(
|
||||
new
|
||||
{
|
||||
context.Response,
|
||||
nextCalled
|
||||
});
|
||||
}
|
||||
```
|
||||
<sup><a href='/src/Tests/Snippets/MyMiddlewareTests.cs#L10-L32' title='File snippet `mymiddlewaretest` was extracted from'>snippet source</a> | <a href='#snippet-mymiddlewaretest' title='Navigate to start of snippet `mymiddlewaretest`'>anchor</a></sup>
|
||||
<!-- endsnippet -->
|
||||
|
||||
Will result in the following verified file:
|
||||
|
||||
<!-- snippet: MyMiddlewareTests.Test.verified.txt -->
|
||||
<a id='snippet-MyMiddlewareTests.Test.verified.txt'/></a>
|
||||
```txt
|
||||
{
|
||||
Response: {
|
||||
Headers: {
|
||||
headerKey: 'headerValue'
|
||||
}
|
||||
},
|
||||
nextCalled: true
|
||||
}
|
||||
```
|
||||
<sup><a href='/src/Tests/Snippets/MyMiddlewareTests.Test.verified.txt#L1-L8' title='File snippet `MyMiddlewareTests.Test.verified.txt` was extracted from'>snippet source</a> | <a href='#snippet-MyMiddlewareTests.Test.verified.txt' title='Navigate to start of snippet `MyMiddlewareTests.Test.verified.txt`'>anchor</a></sup>
|
||||
<!-- endsnippet -->
|
||||
|
||||
|
||||
## Icon
|
||||
|
||||
[Spider](https://thenounproject.com/term/spider/904683/) designed by [marialuisa iborra](https://thenounproject.com/marialuisa.iborra/) from [The Noun Project](https://thenounproject.com/creativepriyanka).
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Verify.Web;
|
||||
using Verify.EntityFramework;
|
||||
using Xunit;
|
||||
|
||||
[GlobalSetUp]
|
||||
|
@ -7,7 +7,7 @@ public static class GlobalSetup
|
|||
public static void Setup()
|
||||
{
|
||||
#region Enable
|
||||
VerifyWeb.Enable();
|
||||
VerifyEntityFramework.Enable();
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
using System.Threading.Tasks;
|
||||
using EfLocalDb;
|
||||
|
||||
// LocalDb is used to make the sample simpler.
|
||||
// Replace with a real DbContext
|
||||
public static class DbContextBuilder
|
||||
{
|
||||
static DbContextBuilder()
|
||||
{
|
||||
sqlInstance = new SqlInstance<SampleDbContext>(
|
||||
buildTemplate: CreateDb,
|
||||
constructInstance: builder => new SampleDbContext(builder.Options));
|
||||
}
|
||||
|
||||
static SqlInstance<SampleDbContext> sqlInstance;
|
||||
|
||||
static async Task CreateDb(SampleDbContext context)
|
||||
{
|
||||
await context.Database.EnsureCreatedAsync();
|
||||
|
||||
var company1 = new Company
|
||||
{
|
||||
Id = 1,
|
||||
Content = "Company1"
|
||||
};
|
||||
var employee1 = new Employee
|
||||
{
|
||||
Id = 2,
|
||||
CompanyId = company1.Id,
|
||||
Content = "Employee1",
|
||||
Age = 25
|
||||
};
|
||||
var employee2 = new Employee
|
||||
{
|
||||
Id = 3,
|
||||
CompanyId = company1.Id,
|
||||
Content = "Employee2",
|
||||
Age = 31
|
||||
};
|
||||
var company2 = new Company
|
||||
{
|
||||
Id = 4,
|
||||
Content = "Company2"
|
||||
};
|
||||
var employee4 = new Employee
|
||||
{
|
||||
Id = 5,
|
||||
CompanyId = company2.Id,
|
||||
Content = "Employee4",
|
||||
Age = 34
|
||||
};
|
||||
var company3 = new Company
|
||||
{
|
||||
Id = 6,
|
||||
Content = "Company3"
|
||||
};
|
||||
var company4 = new Company
|
||||
{
|
||||
Id = 7,
|
||||
Content = "Company4"
|
||||
};
|
||||
context.AddRange(company1, employee1, employee2, company2, company3, company4, employee4);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public static Task<SqlDatabase<SampleDbContext>> GetDatabase(string suffix)
|
||||
{
|
||||
return sqlInstance.Build(suffix);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
public class MyController :
|
||||
Controller
|
||||
{
|
||||
public ActionResult<List<DataItem>> Method(string input)
|
||||
{
|
||||
var headers = HttpContext.Response.Headers;
|
||||
headers.Add("headerKey", "headerValue");
|
||||
headers.Add("receivedInput", input);
|
||||
|
||||
var cookies = HttpContext.Response.Cookies;
|
||||
cookies.Append("cookieKey", "cookieValue");
|
||||
|
||||
var items = new List<DataItem>
|
||||
{
|
||||
new DataItem("Value1"),
|
||||
new DataItem("Value2")
|
||||
};
|
||||
return new ActionResult<List<DataItem>>(items);
|
||||
}
|
||||
|
||||
public class DataItem
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public DataItem(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using VerifyXunit;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public class MyControllerTests :
|
||||
VerifyBase
|
||||
{
|
||||
#region MyControllerTest
|
||||
[Fact]
|
||||
public Task Test()
|
||||
{
|
||||
var context = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext()
|
||||
};
|
||||
var controller = new MyController
|
||||
{
|
||||
ControllerContext = context
|
||||
};
|
||||
|
||||
var result = controller.Method("inputValue");
|
||||
return Verify(
|
||||
new
|
||||
{
|
||||
result,
|
||||
context
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
public MyControllerTests(ITestOutputHelper output) :
|
||||
base(output)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.Threading.Tasks;
|
||||
using VerifyXunit;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public class Usage :
|
||||
VerifyBase
|
||||
{
|
||||
#region MyControllerTest
|
||||
[Fact]
|
||||
public async Task ChangeTracked()
|
||||
{
|
||||
var database = await DbContextBuilder.GetDatabase("ChangeTracked");
|
||||
var employee = await database.Context.Employees.FindAsync(3);
|
||||
employee.Age++;
|
||||
await Verify(database.Context);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public Usage(ITestOutputHelper output) :
|
||||
base(output)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,29 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using VerifyXunit;
|
||||
using Xunit;
|
||||
using VerifyXunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public class Tests :
|
||||
VerifyBase
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public Task ChallengeResult()
|
||||
{
|
||||
var result = new ChallengeResult(
|
||||
"scheme",
|
||||
new AuthenticationProperties(
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{"key", "value"}
|
||||
}));
|
||||
return VerifyResult(result);
|
||||
}
|
||||
|
||||
|
||||
public Tests(ITestOutputHelper output) :
|
||||
base(output)
|
||||
{
|
||||
|
|
|
@ -16,4 +16,9 @@
|
|||
<PackageReference Include="ProjectDefaults" Version="1.0.40" PrivateAssets="All" />
|
||||
<ProjectReference Include="..\Verify.EntityFramework\Verify.EntityFramework.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Snippets\Usage.Test.verified.txt">
|
||||
<DependentUpon>Usage.cs</DependentUpon>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,11 +1,14 @@
|
|||
using Newtonsoft.Json;
|
||||
using Verify;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Newtonsoft.Json;
|
||||
using Verify;
|
||||
|
||||
class EntityEntryConverter :
|
||||
WriteOnlyJsonConverter<EntityEntry>
|
||||
class DbContextConverter :
|
||||
WriteOnlyJsonConverter<DbContext>
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, EntityEntry? context, JsonSerializer serializer)
|
||||
public override void WriteJson(JsonWriter writer, DbContext? context, JsonSerializer serializer)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
|
@ -14,9 +17,22 @@ class EntityEntryConverter :
|
|||
|
||||
writer.WriteStartObject();
|
||||
|
||||
//HttpResponseConverter.WriteProperties(writer, serializer, response);
|
||||
foreach (var entry in context.ChangeTracker.Entries()
|
||||
.Where(x => x.State != EntityState.Unchanged))
|
||||
{
|
||||
foreach (var property in entry.ChangedProperties())
|
||||
{
|
||||
writer.WritePropertyName(property.Metadata.Name);
|
||||
serializer.Serialize(
|
||||
writer,
|
||||
new
|
||||
{
|
||||
Original = property.OriginalValue,
|
||||
Current = property.CurrentValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
|
||||
static class Extensions
|
||||
{
|
||||
public static IEnumerable<PropertyEntry> ChangedProperties(this EntityEntry entry)
|
||||
{
|
||||
return entry.Properties
|
||||
.Where(x => x.IsModified);
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
settings.AddExtraSettings(serializer =>
|
||||
{
|
||||
var converters = serializer.Converters;
|
||||
converters.Add(new EntityEntryConverter());
|
||||
converters.Add(new DbContextConverter());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче