-
Notifications
You must be signed in to change notification settings - Fork 6k
Unit testing and mocking #36110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Unit testing and mocking #36110
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
06b05f6
initial commit
alexwolfmsft 3815632
Apply suggestions from code review
alexwolfmsft 8b012a3
pr changes
alexwolfmsft aa29e05
Merge
alexwolfmsft 0a4f450
updates
alexwolfmsft 092d704
fix warnings
alexwolfmsft 952df14
link fixes
alexwolfmsft d6d3fad
verbiage
alexwolfmsft dba84f2
added toc
alexwolfmsft c568045
fix typo
alexwolfmsft 7020570
tweaks
alexwolfmsft 6f43656
fixed linter
alexwolfmsft 2d35fee
updated code samples
alexwolfmsft e45aaf7
fix typo
alexwolfmsft ff77752
Update docs/azure/sdk/unit-testing-mocking.md
IEvangelist b8945c8
Update docs/azure/sdk/unit-testing-mocking.md
IEvangelist dbfa1e1
Apply suggestions from code review
alexwolfmsft 635489c
Apply suggestions from code review
alexwolfmsft 8832e4d
toc
alexwolfmsft 647037e
Apply suggestions from code review
alexwolfmsft f92fe66
Apply suggestions from code review
alexwolfmsft ac29686
Merge branch 'sdk-mocking' of https://github.com/alexwolfmsft/docs in…
alexwolfmsft cd2f620
Apply suggestions from code review
alexwolfmsft 728a9e9
tabs
alexwolfmsft 9a52fd9
test
alexwolfmsft 879b9d4
snippets test
alexwolfmsft bb24d01
fixed references
alexwolfmsft d0626f7
test refactoring
alexwolfmsft 91c794f
fixed code examples
alexwolfmsft fab1033
refactor
alexwolfmsft 1887cd8
Apply suggestions from code review
alexwolfmsft e0f62fc
added NSubstitute
alexwolfmsft 7e31736
added nsubstitute tabs
alexwolfmsft 70c3733
Merge branch 'sdk-mocking' of https://github.com/alexwolfmsft/docs in…
alexwolfmsft 6ae919c
renaming
alexwolfmsft 65736c5
removed unnecessary project
alexwolfmsft ab64050
fixed code sample
alexwolfmsft 4c92a65
updated code samples
alexwolfmsft f4729fc
Apply suggestions from code review
alexwolfmsft 38470d1
updated snippets
alexwolfmsft 8934a67
Merge branch 'sdk-mocking' of https://github.com/alexwolfmsft/docs in…
alexwolfmsft 0677c5b
Update docs/azure/sdk/unit-testing-mocking.md
alexwolfmsft bd58529
fixed return
alexwolfmsft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
docs/azure/sdk/snippets/unit-testing/AboutToExpireSecretsFinder.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using Azure.Security.KeyVault.Secrets; | ||
|
||
public class AboutToExpireSecretFinder | ||
{ | ||
private readonly TimeSpan _threshold; | ||
private readonly SecretClient _client; | ||
|
||
public AboutToExpireSecretFinder(TimeSpan threshold, SecretClient client) | ||
{ | ||
_threshold = threshold; | ||
_client = client; | ||
} | ||
|
||
public async Task<string[]> GetAboutToExpireSecretsAsync() | ||
{ | ||
List<string> secretsAboutToExpire = new(); | ||
|
||
await foreach (var secret in _client.GetPropertiesOfSecretsAsync()) | ||
{ | ||
if (secret.ExpiresOn.HasValue && | ||
secret.ExpiresOn.Value - DateTimeOffset.Now <= _threshold) | ||
{ | ||
secretsAboutToExpire.Add(secret.Name); | ||
} | ||
} | ||
|
||
return secretsAboutToExpire.ToArray(); | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
docs/azure/sdk/snippets/unit-testing/Moq/AboutToExpireSecretsFinderTests_Moq.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
using Azure; | ||
using Azure.Security.KeyVault.Secrets; | ||
using Moq; | ||
|
||
namespace UnitTestingSampleApp.Moq; | ||
|
||
public class AboutToExpireSecretFinderTests_Moq | ||
{ | ||
[Fact] | ||
public async Task DoesNotReturnNonExpiringSecrets() | ||
{ | ||
// Arrange | ||
// Create a page of enumeration results | ||
Page<SecretProperties> page = Page<SecretProperties>.FromValues(new[] | ||
{ | ||
new SecretProperties("secret1") { ExpiresOn = null }, | ||
new SecretProperties("secret2") { ExpiresOn = null } | ||
}, null, Mock.Of<Response>()); | ||
|
||
// Create a pageable that consists of a single page | ||
AsyncPageable<SecretProperties> pageable = | ||
AsyncPageable<SecretProperties>.FromPages(new[] { page }); | ||
|
||
// Setup a client mock object to return the pageable | ||
var clientMock = new Mock<SecretClient>(); | ||
clientMock.Setup(c => c.GetPropertiesOfSecretsAsync(It.IsAny<CancellationToken>())) | ||
.Returns(pageable); | ||
|
||
// Create an instance of a class to test passing in the mock client | ||
var finder = new AboutToExpireSecretFinder(TimeSpan.FromDays(2), clientMock.Object); | ||
|
||
// Act | ||
string[] soonToExpire = await finder.GetAboutToExpireSecretsAsync(); | ||
|
||
// Assert | ||
Assert.Empty(soonToExpire); | ||
} | ||
|
||
[Fact] | ||
public async Task ReturnsSecretsThatExpireSoon() | ||
{ | ||
// Arrange | ||
|
||
// Create a page of enumeration results | ||
DateTimeOffset now = DateTimeOffset.Now; | ||
Page<SecretProperties> page = Page<SecretProperties>.FromValues(new[] | ||
{ | ||
new SecretProperties("secret1") { ExpiresOn = now.AddDays(1) }, | ||
new SecretProperties("secret2") { ExpiresOn = now.AddDays(2) }, | ||
new SecretProperties("secret3") { ExpiresOn = now.AddDays(3) } | ||
}, null, Mock.Of<Response>()); | ||
|
||
// Create a pageable that consists of a single page | ||
AsyncPageable<SecretProperties> pageable = | ||
AsyncPageable<SecretProperties>.FromPages(new[] { page }); | ||
|
||
// Setup a client mock object to return the pageable | ||
var clientMock = new Mock<SecretClient>(); | ||
clientMock.Setup(c => c.GetPropertiesOfSecretsAsync(It.IsAny<CancellationToken>())) | ||
.Returns(pageable); | ||
|
||
// Create an instance of a class to test passing in the mock client | ||
var finder = new AboutToExpireSecretFinder(TimeSpan.FromDays(2), clientMock.Object); | ||
|
||
// Act | ||
string[] soonToExpire = await finder.GetAboutToExpireSecretsAsync(); | ||
|
||
// Assert | ||
Assert.Equal(new[] { "secret1", "secret2" }, soonToExpire); | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
docs/azure/sdk/snippets/unit-testing/Moq/TestSnippets_Moq.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
using Azure.Security.KeyVault.Secrets; | ||
using Azure; | ||
using Moq; | ||
|
||
namespace UnitTestingSampleApp.Moq; | ||
|
||
public class TestSnippets_Moq | ||
{ | ||
public void ServiceClientSnippets() | ||
{ | ||
// <MockSecretClient> | ||
KeyVaultSecret keyVaultSecret = SecretModelFactory.KeyVaultSecret( | ||
new SecretProperties("secret"), "secretValue"); | ||
|
||
Mock<SecretClient> clientMock = new Mock<SecretClient>(); | ||
clientMock.Setup(c => c.GetSecret( | ||
It.IsAny<string>(), | ||
It.IsAny<string>(), | ||
It.IsAny<CancellationToken>()) | ||
) | ||
.Returns(Response.FromValue(keyVaultSecret, Mock.Of<Response>())); | ||
|
||
clientMock.Setup(c => c.GetSecretAsync( | ||
It.IsAny<string>(), | ||
It.IsAny<string>(), | ||
It.IsAny<CancellationToken>()) | ||
) | ||
.ReturnsAsync(Response.FromValue(keyVaultSecret, Mock.Of<Response>())); | ||
|
||
SecretClient secretClient = clientMock.Object; | ||
// </MockSecretClient> | ||
} | ||
|
||
public void ResponseTypeSnippets() | ||
{ | ||
// <MockResponse> | ||
Mock<Response> responseMock = new Mock<Response>(); | ||
responseMock.SetupGet(r => r.Status).Returns(200); | ||
|
||
Response response = responseMock.Object; | ||
// </MockResponse> | ||
} | ||
|
||
public void ResponseTypeTSnippets() | ||
{ | ||
// <MockResponseT> | ||
KeyVaultSecret keyVaultSecret = SecretModelFactory.KeyVaultSecret( | ||
new SecretProperties("secret"), "secretValue"); | ||
Response<KeyVaultSecret> response = Response.FromValue(keyVaultSecret, Mock.Of<Response>()); | ||
// </MockResponseT> | ||
} | ||
|
||
public void PaggingSnippets() | ||
{ | ||
// <SingleResponsePage> | ||
Page<SecretProperties> responsePage = Page<SecretProperties>.FromValues( | ||
new[] { | ||
new SecretProperties("secret1"), | ||
new SecretProperties("secret2") | ||
}, | ||
continuationToken: null, | ||
Mock.Of<Response>()); | ||
// </SingleResponsePage> | ||
|
||
// <MultipleResponsePage> | ||
Page<SecretProperties> page1 = Page<SecretProperties>.FromValues( | ||
new[] | ||
{ | ||
new SecretProperties("secret1"), | ||
new SecretProperties("secret2") | ||
}, | ||
"continuationToken", | ||
Mock.Of<Response>()); | ||
|
||
Page<SecretProperties> page2 = Page<SecretProperties>.FromValues( | ||
new[] | ||
{ | ||
new SecretProperties("secret3"), | ||
new SecretProperties("secret4") | ||
}, | ||
"continuationToken2", | ||
Mock.Of<Response>()); | ||
|
||
Page<SecretProperties> lastPage = Page<SecretProperties>.FromValues( | ||
new[] | ||
{ | ||
new SecretProperties("secret5"), | ||
new SecretProperties("secret6") | ||
}, | ||
continuationToken: null, | ||
Mock.Of<Response>()); | ||
|
||
Pageable<SecretProperties> pageable = Pageable<SecretProperties> | ||
.FromPages(new[] { page1, page2, lastPage }); | ||
|
||
AsyncPageable<SecretProperties> asyncPageable = AsyncPageable<SecretProperties> | ||
.FromPages(new[] { page1, page2, lastPage }); | ||
// </MultipleResponsePage> | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
...zure/sdk/snippets/unit-testing/NSubstitute/AboutToExpireSecretsFinderTests_NSubstitute.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
using Azure; | ||
using Azure.Security.KeyVault.Secrets; | ||
using NSubstitute; | ||
|
||
namespace UnitTestingSampleApp.NSubstitute; | ||
|
||
public class AboutToExpireSecretFinderTests_NSubstitute | ||
{ | ||
[Fact] | ||
public async Task DoesNotReturnNonExpiringSecrets() | ||
{ | ||
// Arrange | ||
// Create a page of enumeration results | ||
Page<SecretProperties> page = Page<SecretProperties>.FromValues(new[] | ||
{ | ||
new SecretProperties("secret1") { ExpiresOn = null }, | ||
new SecretProperties("secret2") { ExpiresOn = null } | ||
}, null, Substitute.For<Response>()); | ||
|
||
// Create a pageable that consists of a single page | ||
AsyncPageable<SecretProperties> pageable = | ||
AsyncPageable<SecretProperties>.FromPages(new[] { page }); | ||
|
||
// Setup a client mock object to return the pageable | ||
SecretClient clientMock = Substitute.For<SecretClient>(); | ||
clientMock.GetPropertiesOfSecretsAsync(Arg.Any<CancellationToken>()) | ||
.Returns(pageable); | ||
|
||
// Create an instance of a class to test passing in the mock client | ||
var finder = new AboutToExpireSecretFinder(TimeSpan.FromDays(2), clientMock); | ||
|
||
// Act | ||
var soonToExpire = await finder.GetAboutToExpireSecretsAsync(); | ||
alexwolfmsft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Assert | ||
Assert.Empty(soonToExpire); | ||
} | ||
|
||
[Fact] | ||
public async Task ReturnsSecretsThatExpireSoon() | ||
{ | ||
// Arrange | ||
|
||
// Create a page of enumeration results | ||
DateTimeOffset now = DateTimeOffset.Now; | ||
Page<SecretProperties> page = Page<SecretProperties>.FromValues(new[] | ||
{ | ||
new SecretProperties("secret1") { ExpiresOn = now.AddDays(1) }, | ||
new SecretProperties("secret2") { ExpiresOn = now.AddDays(2) }, | ||
new SecretProperties("secret3") { ExpiresOn = now.AddDays(3) } | ||
}, null,Substitute.For<Response>()); | ||
|
||
// Create a pageable that consists of a single page | ||
AsyncPageable<SecretProperties> pageable = | ||
AsyncPageable<SecretProperties>.FromPages(new[] { page }); | ||
|
||
// Setup a client mock object to return the pageable | ||
SecretClient clientMock = Substitute.For<SecretClient>(); | ||
clientMock.GetPropertiesOfSecretsAsync(Arg.Any<CancellationToken>()) | ||
.Returns(pageable); | ||
|
||
// Create an instance of a class to test passing in the mock client | ||
var finder = new AboutToExpireSecretFinder(TimeSpan.FromDays(2), clientMock); | ||
|
||
// Act | ||
var soonToExpire = await finder.GetAboutToExpireSecretsAsync(); | ||
alexwolfmsft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Assert | ||
Assert.Equal(new[] { "secret1", "secret2" }, soonToExpire); | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
docs/azure/sdk/snippets/unit-testing/NSubstitute/TestSnippets_NSubstitute.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
using Azure.Security.KeyVault.Secrets; | ||
using Azure; | ||
using NSubstitute; | ||
|
||
namespace UnitTestingSampleApp.NSubstitute; | ||
|
||
public class TestSnippets_NSubstitute | ||
{ | ||
public void ServiceClientSnippets() | ||
{ | ||
// <MockSecretClient> | ||
KeyVaultSecret keyVaultSecret = SecretModelFactory.KeyVaultSecret( | ||
new SecretProperties("secret"), "secretValue"); | ||
|
||
SecretClient clientMock = Substitute.For<SecretClient>(); | ||
clientMock.GetSecret( | ||
Arg.Any<string>(), | ||
Arg.Any<string>(), | ||
Arg.Any<CancellationToken>() | ||
) | ||
.Returns(Response.FromValue(keyVaultSecret, Substitute.For<Response>())); | ||
|
||
clientMock.GetSecretAsync( | ||
Arg.Any<string>(), | ||
Arg.Any<string>(), | ||
Arg.Any<CancellationToken>() | ||
) | ||
.Returns(Response.FromValue(keyVaultSecret, Substitute.For<Response>())); | ||
|
||
SecretClient secretClient = clientMock; | ||
// </MockSecretClient> | ||
} | ||
|
||
public void ResponseTypeSnippets() | ||
{ | ||
// <MockResponse> | ||
Response responseMock = Substitute.For<Response>(); | ||
responseMock.Status.Returns(200); | ||
|
||
Response response = responseMock; | ||
// </MockResponse> | ||
} | ||
|
||
public void ResponseTypeTSnippets() | ||
{ | ||
// <MockResponseT> | ||
KeyVaultSecret keyVaultSecret = SecretModelFactory.KeyVaultSecret( | ||
new SecretProperties("secret"), "secretValue"); | ||
Response<KeyVaultSecret> response = Response.FromValue(keyVaultSecret, Substitute.For<Response>()); | ||
// </MockResponseT> | ||
} | ||
|
||
|
||
public void PaggingSnippets() | ||
{ | ||
// <SingleResponsePage> | ||
Page<SecretProperties> responsePage = Page<SecretProperties>.FromValues( | ||
new[] { | ||
new SecretProperties("secret1"), | ||
new SecretProperties("secret2") | ||
}, | ||
continuationToken: null, | ||
Substitute.For<Response>()); | ||
// </SingleResponsePage> | ||
|
||
// <MultipleResponsePage> | ||
Page<SecretProperties> page1 = Page<SecretProperties>.FromValues( | ||
new[] | ||
{ | ||
new SecretProperties("secret1"), | ||
new SecretProperties("secret2") | ||
}, | ||
"continuationToken", | ||
Substitute.For<Response>()); | ||
|
||
Page<SecretProperties> page2 = Page<SecretProperties>.FromValues( | ||
new[] | ||
{ | ||
new SecretProperties("secret3"), | ||
new SecretProperties("secret4") | ||
}, | ||
"continuationToken2", | ||
Substitute.For<Response>()); | ||
|
||
Page<SecretProperties> lastPage = Page<SecretProperties>.FromValues( | ||
new[] | ||
{ | ||
new SecretProperties("secret5"), | ||
new SecretProperties("secret6") | ||
}, | ||
continuationToken: null, | ||
Substitute.For<Response>()); | ||
|
||
Pageable<SecretProperties> pageable = Pageable<SecretProperties> | ||
.FromPages(new[] { page1, page2, lastPage }); | ||
|
||
AsyncPageable<SecretProperties> asyncPageable = AsyncPageable<SecretProperties> | ||
.FromPages(new[] { page1, page2, lastPage }); | ||
// </MultipleResponsePage> | ||
} | ||
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.