Reputation: 49
I'm trying to create a unit test for azure function and getting Unsupported expression: Non-overridable members may not be used in setup / verification expressions.
Here is my Function
public class EmployeeFunction
{
private readonly EmpRepo _repo;
public EmployeeFunction(EmpRepo repo)
{
_repo = repo;
}
[FunctionName("EmployeeFunctionTrigger")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "EmployeeFunction/{empName}")] HttpRequest req, string empName, ILogger log)
{
//code
return _repo.GetEmployeeByName(empName);
}
}
And here is my Repository where I'm injecting the IHttpClientFactory
public class EmpRepo : IEmpRepo
{
private readonly IHttpClientFactory _httpClientFactory;
public EmpRepo (IHttpClientFactory clientFactory)
{
_httpClientFactory = clientFactory;
}
public async Task<Employee> GetEmployeeByName(string name)
{
using HttpClient _httpClient = httpClientFactory.CreateClient("EmpClient"){
//code
}
}
And here is my Test. I'm using Xunit and Moq
public class EmpFunctionTest
{
[Fact]
public async Task Http_trigger_should_return_known_string()
{
// Arrange
var httpClientFactory = new Mock<IHttpClientFactory>();
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
var fixture = new Fixture();
mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(fixture.Create<String>()),
});
var client = new HttpClient(mockHttpMessageHandler.Object);
client.BaseAddress = fixture.Create<Uri>();
httpClientFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
var empRepo= new Mock<EmpRepo>(httpClientFactory.Object);
empRepo.Setup(o => o.GetEmployeeByName(It.IsAny<string>()))
// prepare the expected response of the mocked http call
.ReturnsAsync(new Employee()
{
Name= "Test",
ID= 12345,
})
.Verifiable();
var EmpFuc= new EmployeeFunction(empRepo.Object);
//code for act and assert
}
But getting the exception
System.NotSupportedException : Unsupported expression: o => o.GetEmployeeByName(It.IsAny<string>()) Non-overridable members (here: EmpRepo.GetEmployeeByName) may not be used in setup / verification expressions.
Upvotes: 1
Views: 704
Reputation: 247088
This is an XY problem.
Inject the interface instead of the concrete class into the function.
public class EmployeeFunction {
private readonly IEmpRepo repo;
public EmployeeFunction(IEmpRepo repo) {
this.repo = repo;
}
[FunctionName("EmployeeFunctionTrigger")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "EmployeeFunction/{empName}")] HttpRequest req, string empName, ILogger log) {
//code
var x = await repo.GetEmployeeByName(empName);
//...
}
}
the repo should be a typed client instead of injecting IHttpClientFactory
public class EmpRepo : IEmpRepo {
private readonly HttpClient client;
public EmpRepo (HttpClient client) {
this.client = client;
//this.client.BaseAddress = new Uri("api url"); //(optional)
}
public async Task<Employee> GetEmployeeByName(string name) {
//..use client here
}
}
and configured accordingly
builder.Services.AddHttpClient<IEmpRepo, EmpRepo>(c => {
// c.BaseAddress = new Uri("api url"); // as needed
});
Finally the test should use async Task
and not async void
.
public class EmpFunctionTest {
[Fact]
public async Task Http_trigger_should_return_known_string() {
// Arrange
var fixture = new Fixture().Customize(new AutoMoqCustomization());
Mock<IEmpRepo> empRepo = fixture.Freeze<Mock<IEmpRepo>>();
empRepo
.Setup(o => o.GetEmployeeByName(It.IsAny<string>()))
.ReturnsAsync(new Employee() {
Name = "Test",
ID = 12345,
})
.Verifiable();
EmployeeFunction subject = fixture.Create<EmployeeFunction>();
//...code for act and assert
}
}
Upvotes: 2