Skip to content

Commit

Permalink
add first draft of Azure Functions unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmrdavid committed May 14, 2024
1 parent 7eef072 commit 3f64599
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 10 deletions.
17 changes: 12 additions & 5 deletions Microsoft.DurableTask.sln
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebAPI", "samples\WebAPI\We
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "src\Shared\Shared.csproj", "{57A4C812-B0D9-49E9-9EBE-7E94D3D78ED7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "misc", "misc\misc.csproj", "{1E135970-60CF-470A-9270-4560BFA0A7DF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "misc", "misc\misc.csproj", "{1E135970-60CF-470A-9270-4560BFA0A7DF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.OrchestrationServiceClientShim", "src\Client\OrchestrationServiceClientShim\Client.OrchestrationServiceClientShim.csproj", "{505F6151-6E36-4E0A-A740-14751B8A9397}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client.OrchestrationServiceClientShim", "src\Client\OrchestrationServiceClientShim\Client.OrchestrationServiceClientShim.csproj", "{505F6151-6E36-4E0A-A740-14751B8A9397}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.OrchestrationServiceClientShim.Tests", "test\Client\OrchestrationServiceClientShim.Tests\Client.OrchestrationServiceClientShim.Tests.csproj", "{93E3B973-0FC4-4241-B7BB-064FB538FB50}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client.OrchestrationServiceClientShim.Tests", "test\Client\OrchestrationServiceClientShim.Tests\Client.OrchestrationServiceClientShim.Tests.csproj", "{93E3B973-0FC4-4241-B7BB-064FB538FB50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc", "src\Grpc\Grpc.csproj", "{44AD321D-96D4-481E-BD41-D0B12A619833}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc", "src\Grpc\Grpc.csproj", "{44AD321D-96D4-481E-BD41-D0B12A619833}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "test\Benchmarks\Benchmarks.csproj", "{82C0CD7D-2764-421A-8256-7E2304D5A6E7}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "test\Benchmarks\Benchmarks.csproj", "{82C0CD7D-2764-421A-8256-7E2304D5A6E7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Analyzers", "src\Analyzers\Analyzers.csproj", "{998E9D97-BD36-4A9D-81FC-5DAC1CE40083}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Analyzers.Tests", "test\Analyzers.Tests\Analyzers.Tests.csproj", "{541FCCCE-1059-4691-B027-F761CD80DE92}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureFunctionsUnitTests", "samples\AzureFunctionsUnitTests\AzureFunctionsUnitTests.csproj", "{FC2692E7-79AE-400E-A50F-8E0BCC8C9BD9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -179,6 +181,10 @@ Global
{541FCCCE-1059-4691-B027-F761CD80DE92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{541FCCCE-1059-4691-B027-F761CD80DE92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{541FCCCE-1059-4691-B027-F761CD80DE92}.Release|Any CPU.Build.0 = Release|Any CPU
{FC2692E7-79AE-400E-A50F-8E0BCC8C9BD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC2692E7-79AE-400E-A50F-8E0BCC8C9BD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC2692E7-79AE-400E-A50F-8E0BCC8C9BD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC2692E7-79AE-400E-A50F-8E0BCC8C9BD9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -213,6 +219,7 @@ Global
{82C0CD7D-2764-421A-8256-7E2304D5A6E7} = {E5637F81-2FB9-4CD7-900D-455363B142A7}
{998E9D97-BD36-4A9D-81FC-5DAC1CE40083} = {8AFC9781-F6F1-4696-BB4A-9ED7CA9D612B}
{541FCCCE-1059-4691-B027-F761CD80DE92} = {E5637F81-2FB9-4CD7-900D-455363B142A7}
{FC2692E7-79AE-400E-A50F-8E0BCC8C9BD9} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AB41CB55-35EA-4986-A522-387AB3402E71}
Expand Down
4 changes: 0 additions & 4 deletions samples/AzureFunctionsApp/AzureFunctionsApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ public static class AzureFunctionsApp
public static async Task<List<string>> RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
ILogger logger = context.CreateReplaySafeLogger(nameof(AzureFunctionsApp));
logger.LogInformation("Saying hello.");
var outputs = new List<string>();

// Replace name and input with values relevant for your Durable Functions Activity
Expand All @@ -31,8 +29,6 @@ public static async Task<List<string>> RunOrchestrator(
[Function(nameof(SayHello))]
public static string SayHello([ActivityTrigger] string name, FunctionContext executionContext)
{
ILogger logger = executionContext.GetLogger("SayHello");
logger.LogInformation($"Saying hello to {name}.");
return $"Hello {name}!";
}

Expand Down
28 changes: 28 additions & 0 deletions samples/AzureFunctionsUnitTests/AzureFunctionsUnitTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
<PackageReference Include="moq" Version="4.20.70" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AzureFunctionsApp\AzureFunctionsApp.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

</Project>
49 changes: 49 additions & 0 deletions samples/AzureFunctionsUnitTests/SampleUnitTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace Company.Function; // same namespace as the Azure Functions app

using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask;
using Moq;

public class SampleUnitTests
{
[Fact]
public async Task OrchestrationReturnsMultipleGreetings()
{
// create mock orchestration context, and mock ILogger.
var contextMock = new Mock<TaskOrchestrationContext>();

// mock activity results
// In Moq, optional arguments need to be specified as well. We specify them with It.IsAny<T>(), where T is the type of the optional argument
contextMock.Setup(x => x.CallActivityAsync<string>(nameof(AzureFunctionsApp.SayHello), "Tokyo", It.IsAny<TaskOptions>()))
.ReturnsAsync("Hello Tokyo!");
contextMock.Setup(x => x.CallActivityAsync<string>(nameof(AzureFunctionsApp.SayHello), "Seattle", It.IsAny<TaskOptions>()))
.ReturnsAsync("Hello Seattle!");
contextMock.Setup(x => x.CallActivityAsync<string>(nameof(AzureFunctionsApp.SayHello), "London", It.IsAny<TaskOptions>()))
.ReturnsAsync("Hello London!");

// execute the orchestrator
var contextObj = contextMock.Object;
List<string> outputs = await AzureFunctionsApp.RunOrchestrator(contextObj);

// assert expected outputs
Assert.Equal(3, outputs.Count);
Assert.Equal("Hello Tokyo!", outputs[0]);
Assert.Equal("Hello Seattle!", outputs[1]);
Assert.Equal("Hello London!", outputs[2]);
}

[Fact]
public void ActivityReturnsGreeting()
{
var contextMock = new Mock<FunctionContext>();
var context = contextMock.Object;

string output = AzureFunctionsApp.SayHello("Tokyo", context);

// assert expected outputs
Assert.Equal("Hello Tokyo!", output);
}
}
2 changes: 1 addition & 1 deletion src/Abstractions/TaskOrchestrationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ public virtual Task CallSubOrchestratorAsync(
/// </summary>
/// <param name="categoryName">The logger's category name.</param>
/// <returns>An instance of <see cref="ILogger"/> that is replay-safe.</returns>
public ILogger CreateReplaySafeLogger(string categoryName)
public virtual ILogger CreateReplaySafeLogger(string categoryName)
=> new ReplaySafeLogger(this, this.LoggerFactory.CreateLogger(categoryName));

/// <inheritdoc cref="CreateReplaySafeLogger(string)" />
Expand Down

0 comments on commit 3f64599

Please sign in to comment.