Skip to content

Commit 8c40036

Browse files
committed
Update README.md and seperated tests for Dapper.
1 parent 834ab36 commit 8c40036

File tree

7 files changed

+229
-61
lines changed

7 files changed

+229
-61
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ There can be multiple data seeding classes. To create a new data seeding class:
5656
1. Create a new data seeding class in the same folder inheriting from [IDataSeeder](src/DeviceManager.Api/Data/DataSeed/IDataSeeder.cs) interface.
5757
2. Register new class in the [IocContainerConfiguration](src/DeviceManager.Api/Configuration/IocContainerConfiguration.cs) class by replacing `DataSeeder` with new class name.
5858

59+
## Dapper support
60+
61+
Dapper is incorporated into the application. [DapperUnitOfWork](src/DeviceManager.Api/Data/Management/Dapper/DapperUnitOfWork.cs) handles all the begin and commit transaction. The instance of Dapper Unit of work can be obtained by requesting instance of [IDapperUnitOfWork](src/DeviceManager.Api/Data/Management/Dapper/IDapperUnitOfWork.cs).
62+
63+
[DeviceService](src/DeviceManager.Api/Services/DeviceService.cs) is using [DapperUnitOfWork](src/DeviceManager.Api/Data/Management/Dapper/DapperUnitOfWork.cs) to fetch and create records in the database through [DapperRepository](src/DeviceManager.Api/Data/Management/Dapper/DapperRepository.cs). [DapperRepository](src/DeviceManager.Api/Data/Management/Dapper/DapperRepository.cs) is a generic repository with built in methods for fetching and adding records into the database based on [DapperInsert](src/DeviceManager.Api/Attributes/Dapper/DapperInsertAttribute.cs) and [DapperUpdate](src/DeviceManager.Api/Attributes/Dapper/DapperUpdateAttribute.cs) attributes defined on the Model. In the future update and delete will be implemented.
64+
65+
The [DapperRepository](src/DeviceManager.Api/Data/Management/Dapper/DapperRepository.cs) builds generic `insert` and `fetch` using [QueryBuilderHelper](src/DeviceManager.Api/Helpers/Dapper/QueryBuilderHelper.cs) class based on the attributes defined on the model. For example [Device](src/DeviceManager.Api/Data/Model/Device.cs) model defines `DapperInsert` on few properties. Only these property names will be considered while building `insert query`.
66+
67+
The `Dapper` region in the [DeviceController](src/DeviceManager.Api/Controllers/DevicesController.cs) uses Dapper to fetch and create records in the database.
68+
5969
## Docker support
6070

6171
App images available in Docker Hub Registry: https://hub.docker.com/r/boriszn/devicemanagerapi/ (**LINUX and Windows images are available**)

src/DeviceManager.Api/Data/Management/Dapper/DapperUnitOfWork.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
namespace DeviceManager.Api.Data.Management.Dapper
66
{
77
/// <summary>
8-
///
8+
/// Dapper Unit of work for maintaining the transaction
99
/// </summary>
10-
/// <typeparam name="T"></typeparam>
1110
public class DapperUnitOfWork : IDapperUnitOfWork, IDisposable
1211
{
1312
private IDbConnection connection;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using DeviceManager.Api.Constants;
2+
using DeviceManager.Api.Model;
3+
using DeviceManager.Api.UnitTests.Builders;
4+
using FluentAssertions;
5+
using System.Net;
6+
using System.Threading.Tasks;
7+
using Xunit;
8+
9+
namespace DeviceManager.Api.UnitTests.Api
10+
{
11+
/// <summary>
12+
///
13+
/// </summary>
14+
[Trait("Category", "Integration")]
15+
public class DeviceApiWithDapperTests
16+
{
17+
[Fact]
18+
public async Task GetDevices_WithValidParameters_ReturnsOkResult()
19+
{
20+
// Arrange and Act
21+
var devicesApiBuilder = await new DevicesApiBuilder()
22+
.WithClientCredentials();
23+
24+
devicesApiBuilder = await devicesApiBuilder.QueryWithDapper(page: 1, pageCount: 5, version: "1.0")
25+
//.WithTenantId("b0ed668d-7ef2-4a23-a333-94ad278f45d7")
26+
.WithTenantId(DefaultConstants.DefaultTenantGuid)
27+
.Get();
28+
29+
// Assert
30+
devicesApiBuilder.HttpResponseMessage.StatusCode.Should().Be(HttpStatusCode.OK);
31+
}
32+
33+
#if UseAuthentication
34+
35+
[Fact]
36+
public async Task GetDevices_WithoutAuthentication_ReturnsUnauthorized()
37+
{
38+
// Arrange and Act
39+
var devicesApiBuilder = await new DevicesApiBuilder().QueryWithDapper(page: 1, pageCount: 5, version: "1.0")
40+
//.WithTenantId("b0ed668d-7ef2-4a23-a333-94ad278f45d7")
41+
.WithTenantId(DefaultConstants.DefaultTenantGuid)
42+
.Get();
43+
44+
// Assert
45+
devicesApiBuilder.HttpResponseMessage.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
46+
}
47+
#endif
48+
[Fact(
49+
Skip = "The tests will add a new item to real DB, thus should be run manually"
50+
)]
51+
public async Task PostDevice_WithDeviceModel_ReturnsOkResult()
52+
{
53+
// Arrange and Act
54+
var devicesApiBuilder = await new DevicesApiBuilder()
55+
.WithClientCredentials();
56+
57+
devicesApiBuilder = await devicesApiBuilder.DefaultDapperQuery(version: "1.0")
58+
.WithDeviceViewModelData(new DeviceViewModel()
59+
{
60+
DeviceCode = "DAPPER_DFGRRO12",
61+
Title = "RO Controller"
62+
})
63+
.WithTenantId(DefaultConstants.DefaultTenantGuid)
64+
.Post();
65+
66+
// Assert
67+
devicesApiBuilder.HttpResponseMessage.StatusCode
68+
.Should().Be(HttpStatusCode.OK);
69+
}
70+
}
71+
}

test/DeviceManager.Api.UnitTests/Builders/DevicesApiBuilder.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ public DevicesApiBuilder DefaultQuery(string version)
4242
return this;
4343
}
4444

45+
public DevicesApiBuilder DefaultDapperQuery(string version)
46+
{
47+
query = $"api/v{version}/devices/dapper";
48+
49+
return this;
50+
}
51+
4552
/// <summary>
4653
/// Queries with parameters.
4754
/// </summary>
@@ -56,6 +63,13 @@ public DevicesApiBuilder QueryWith(int page, int pageCount, string version)
5663
return this;
5764
}
5865

66+
public DevicesApiBuilder QueryWithDapper(int page, int pageCount, string version)
67+
{
68+
query = $"api/v{version}/devices/dapper?page={page}&pageSize={pageCount}";
69+
70+
return this;
71+
}
72+
5973
public DevicesApiBuilder QueryWithDeviceId(string deviceId, string version)
6074
{
6175
query = $"api/v{version}/devices/{deviceId}";
@@ -161,5 +175,17 @@ public async Task<DevicesApiBuilder> Post()
161175
HttpResponseMessage = await testContextFactory.Client.PostAsync(query, stringContent);
162176
return this;
163177
}
178+
179+
public async Task<DevicesApiBuilder> PostUsingDapper()
180+
{
181+
// Build Post data context from json string
182+
var stringContent = new StringContent(
183+
deviceViewModelData,
184+
Encoding.UTF8,
185+
"application/json");
186+
187+
HttpResponseMessage = await testContextFactory.Client.PostAsync(query, stringContent);
188+
return this;
189+
}
164190
}
165191
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using DeviceManager.Api.Data.Management.Dapper;
2+
using Moq;
3+
using System.Data;
4+
using Xunit;
5+
6+
namespace DeviceManager.Api.UnitTests.Data.Management
7+
{
8+
public class DapperUnitOfWorkTests
9+
{
10+
[Fact]
11+
public void Commit_WillCallSaveChangesOnce()
12+
{
13+
// Arrange
14+
var mockConnection = new Mock<IDbConnection>();
15+
var mockTransaction = new Mock<IDbTransaction>();
16+
var mockConnectionFactory = new Mock<IConnectionFactory>();
17+
18+
mockConnection.Setup(mc => mc.BeginTransaction()).Returns(mockTransaction.Object);
19+
20+
mockConnectionFactory.Setup(cf => cf.Connection).Returns(mockConnection.Object);
21+
22+
var dapperUnitOfWork = new DapperUnitOfWork(mockConnectionFactory.Object);
23+
24+
// Act
25+
dapperUnitOfWork.BeginTransaction();
26+
27+
dapperUnitOfWork.Commit();
28+
29+
//// Assert
30+
mockTransaction.Verify(x => x.Commit(), Times.Once);
31+
}
32+
}
33+
}

test/DeviceManager.Api.UnitTests/Services/DeviceServiceTests.cs

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ public class DeviceServiceTests : IDisposable
1515
{
1616
private readonly IDeviceService service;
1717

18-
private readonly IDeviceService serviceUsingDapper;
19-
2018
public DeviceServiceTests()
2119
{
2220
// Build Device
@@ -34,13 +32,6 @@ public DeviceServiceTests()
3432
.WithValidationMock()
3533
.WithUnitOfWorkSetup()
3634
.Build();
37-
38-
// Build device service with dapper UOW
39-
serviceUsingDapper = new DeviceServiceBuilder()
40-
.WithDapperRepositoryMock(devicesList, device)
41-
.WithValidationMock()
42-
.WithDapperUnitOfWorkSetup()
43-
.Build();
4435
}
4536

4637
public void Dispose()
@@ -49,8 +40,6 @@ public void Dispose()
4940
// this.mockRepository.VerifyAll();
5041
}
5142

52-
#region Entity Framework Core
53-
5443
[Fact]
5544
public void CreateDevice_WithValidParameters_SholdNotTrowAnyExceptions()
5645
{
@@ -131,53 +120,5 @@ public void UpdateDevice_WithValidParameters_SholdNotThrowAnyExceptions()
131120
// Assert
132121
action.Should().NotThrow();
133122
}
134-
135-
#endregion
136-
137-
#region Dapper
138-
139-
[Fact]
140-
public void CreateDevice_WithDapper_WithValidParameters_SholdNotThrowAnyExceptions()
141-
{
142-
// Arrange
143-
var deviceViewModel = new DeviceViewModel
144-
{
145-
Title = String.Empty,
146-
DeviceCode = String.Empty,
147-
};
148-
149-
// Act
150-
Func<Task> comparison = async () => { await serviceUsingDapper.CreateDeviceUsingDapperAsync(deviceViewModel); };
151-
152-
// Assert
153-
comparison.Should().NotThrow();
154-
}
155-
156-
[Fact]
157-
public void GetDevices_WithDapper_WithValidParameters_SholdNotThrowAnyExceptions()
158-
{
159-
// Arrange
160-
161-
// Act
162-
Func<Task> comparison = async () => { await serviceUsingDapper.GetDevicesUsingDapper(1, 1); };
163-
164-
// Assert
165-
comparison.Should().NotThrow();
166-
}
167-
168-
[Fact]
169-
public async void GetDevices_WithDapper_WithValidParameters_ShouldHaveOneElement()
170-
{
171-
// Arrange
172-
173-
// Act
174-
IList<DeviceViewModel> devices = await serviceUsingDapper.GetDevicesUsingDapper(1, 1);
175-
176-
// Assert
177-
devices.Should().NotBeNull();
178-
devices.Should().HaveCount(1);
179-
}
180-
181-
#endregion
182123
}
183124
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using DeviceManager.Api.Data.Model;
2+
using DeviceManager.Api.Model;
3+
using DeviceManager.Api.Services;
4+
using DeviceManager.Api.UnitTests.Builders;
5+
using FluentAssertions;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Threading.Tasks;
9+
using Xunit;
10+
11+
namespace DeviceManager.Api.UnitTests.Services
12+
{
13+
public class DeviceServiceWithDapperTests : IDisposable
14+
{
15+
private readonly IDeviceService service;
16+
17+
/// <summary>
18+
/// Test device services using dapper
19+
/// </summary>
20+
public DeviceServiceWithDapperTests()
21+
{
22+
// Build Device
23+
Device device = new DeviceBuilder()
24+
.WithId("27be25a2-1b69-4476-a90f-f80498f5e2ec")
25+
.WithTitle("Raspberry3")
26+
.Build();
27+
28+
// Build Device list
29+
List<Device> devicesList = new List<Device> { device };
30+
31+
32+
// Build device service with dapper UOW
33+
service = new DeviceServiceBuilder()
34+
.WithDapperRepositoryMock(devicesList, device)
35+
.WithValidationMock()
36+
.WithDapperUnitOfWorkSetup()
37+
.Build();
38+
}
39+
40+
public void Dispose()
41+
{
42+
// TODO: Correct verification
43+
// this.mockRepository.VerifyAll();
44+
}
45+
46+
[Fact]
47+
public void CreateDevice_WithValidParameters_SholdNotThrowAnyExceptions()
48+
{
49+
// Arrange
50+
var deviceViewModel = new DeviceViewModel
51+
{
52+
Title = String.Empty,
53+
DeviceCode = String.Empty,
54+
};
55+
56+
// Act
57+
Func<Task> comparison = async () => { await service.CreateDeviceUsingDapperAsync(deviceViewModel); };
58+
59+
// Assert
60+
comparison.Should().NotThrow();
61+
}
62+
63+
[Fact]
64+
public void GetDevices_WithValidParameters_SholdNotThrowAnyExceptions()
65+
{
66+
// Arrange
67+
68+
// Act
69+
Func<Task> comparison = async () => { await service.GetDevicesUsingDapper(1, 1); };
70+
71+
// Assert
72+
comparison.Should().NotThrow();
73+
}
74+
75+
[Fact]
76+
public async void GetDevices_WithValidParameters_ShouldHaveOneElement()
77+
{
78+
// Arrange
79+
80+
// Act
81+
IList<DeviceViewModel> devices = await service.GetDevicesUsingDapper(1, 1);
82+
83+
// Assert
84+
devices.Should().NotBeNull();
85+
devices.Should().HaveCount(1);
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)