I'm getting the following exception when trying to setup the moq for an IConfidentialClientApplication:
System.NotSupportedException : Unsupported expression: ... =>
....ExecuteAsync() Non-overridable members (here:
AbstractAcquireTokenParameterBuilder.ExecuteAsync)
may not be used in setup / verification expressions.
private Mock<IConfidentialClientApplication> _appMock = new Mock<IConfidentialClientApplication>();
[Fact]
public async Task GetAccessTokenResultAsync_WithGoodSetup_ReturnsToken()
{
// Leverages MSAL AuthenticationResult constructor meant for mocks in test
var authentication = CreateAuthenticationResult();
// EXCEPTION THROWN HERE
_appMock.Setup(_ => _.AcquireTokenForClient(It.IsAny<string[]>()).ExecuteAsync())
.ReturnsAsync(authentication);
... rest of test ...
}
An AcquireTokenForClientParameterBuilder is returned by _.AcquireTokenForClient; "a builder enabling you to add optional parameters before executing the token request". This is a sealed class, so I can't easily mock this tricky object.
For those curious, CreateAuthenticationResult() is a method that invokes a signature from Microsoft.Identity.Client.AuthenticationResult that was specifically added in by Microsoft for stubbing an AuthenticationResult, as it cannot be mocked since it too is a sealed class.
https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/682
Seeing that AcquireTokenForClientParameterBuilder is provided through an external library, you obviously aren't able to modify it to be more testable. Given that, I'd suggest abstracting that code behind your own interface (kind of applying the Adapter pattern for testing purposes).
Take the following service/test as an example of how you'd currently be using the IConfidentialClientApplication and trying to mock it (which results in the same error you're seeing):
public class MyService
{
private readonly IConfidentialClientApplication _confidentialClientApplication;
public MyService(IConfidentialClientApplication confidentialClientApplication)
{
_confidentialClientApplication = confidentialClientApplication;
}
public async Task<string> GetAccessToken(IEnumerable<string> scopes)
{
AcquireTokenForClientParameterBuilder tokenBuilder = _confidentialClientApplication.AcquireTokenForClient(scopes);
AuthenticationResult token = await tokenBuilder.ExecuteAsync();
return token.AccessToken;
}
}
public class UnitTest1
{
[Fact]
public async Task Test1()
{
Mock<IConfidentialClientApplication> _appMock = new Mock<IConfidentialClientApplication>();
AuthenticationResult authentication = CreateAuthenticationResult("myToken");
_appMock
.Setup(_ => _.AcquireTokenForClient(It.IsAny<string[]>()).ExecuteAsync())
.ReturnsAsync(authentication);
var myService = new MyService(_appMock.Object);
string accessToken = await myService.GetAccessToken(new string[] { });
Assert.Equal("myToken", accessToken);
}
private AuthenticationResult CreateAuthenticationResult(string accessToken) =>
new AuthenticationResult(accessToken, true, null, DateTimeOffset.Now, DateTimeOffset.Now, string.Empty, null, null, null, Guid.Empty);
}
By introducing a separate interface your code can the simply depend on that, putting you in control of how it will be used/tested:
public interface IIdentityClientAdapter
{
Task<string> GetAccessToken(IEnumerable<string> scopes);
}
public class IdentityClientAdapter : IIdentityClientAdapter
{
private readonly IConfidentialClientApplication _confidentialClientApplication;
public IdentityClientAdapter(IConfidentialClientApplication confidentialClientApplication)
{
_confidentialClientApplication = confidentialClientApplication;
}
public async Task<string> GetAccessToken(IEnumerable<string> scopes)
{
AcquireTokenForClientParameterBuilder tokenBuilder = _confidentialClientApplication.AcquireTokenForClient(scopes);
AuthenticationResult token = await tokenBuilder.ExecuteAsync();
return token.AccessToken;
}
}
public class MyService
{
private readonly IIdentityClientAdapter _identityClientAdapter;
public MyService(IIdentityClientAdapter identityClientAdapter)
{
_identityClientAdapter = identityClientAdapter;
}
public async Task<string> GetAccessToken(IEnumerable<string> scopes)
{
return await _identityClientAdapter.GetAccessToken(scopes);
}
}
public class UnitTest1
{
[Fact]
public async Task Test1()
{
Mock<IIdentityClientAdapter> _appMock = new Mock<IIdentityClientAdapter>();
_appMock
.Setup(_ => _.GetAccessToken(It.IsAny<string[]>()))
.ReturnsAsync("myToken");
var myService = new MyService(_appMock.Object);
string accessToken = await myService.GetAccessToken(new string[] { });
Assert.Equal("myToken", accessToken);
}
}
This example is obviously trivialized, but should still apply. The interface would just need to be fit to your needs.
Related
I want to register consumer by interface, send message, initialize it by interface from container, then consume:
public sealed class TestConsumer<T> : IConsumer<T>
where T : class
{
private readonly Func<ConsumeContext<T>, Task> _onConsume;
private readonly EventWaitHandle _handle;
public TestConsumer(Func<ConsumeContext<T>, Task> onConsume)
{
_onConsume = onConsume;
_handle = new EventWaitHandle(false, EventResetMode.ManualReset);
}
public async Task Consume(ConsumeContext<T> context)
{
try
{
await _onConsume(context).ConfigureAwait(false);
}
finally
{
_handle.Set();
}
}
public async Task GetTask()
{
while (!_handle.WaitOne(0))
await Task.Delay(100);
}
}
public class MyRequest { }
[TestFixture]
public class ConsumerTests
{
[Test]
public async Task Test()
{
var services = new ServiceCollection();
var tc = new TestConsumer<MyRequest>(async (c) => Console.WriteLine("request"));
services.AddSingleton<IConsumer<MyRequest>>(tc);
services.AddSingleton<IBusControl>(x => Bus.Factory.CreateUsingInMemory(cfg =>
{
cfg.ReceiveEndpoint("foobar", c => { c.Consumer<IConsumer<MyRequest>>(x); });
}));
var sp = services.BuildServiceProvider();
await sp.GetRequiredService<IBusControl>().StartAsync();
//and how do I send it?
//this will obviously not work with Uri!!!
var sendEndpoint = await sp.GetRequiredService<IBusControl>().GetSendEndpoint(new Uri("foobar", UriKind.Relative));
await sendEndpoint.Send(new MyRequest());
await tc.GetTask();
Console.WriteLine("done");
}
}
Honestly, lack of documentation is driving me crazy. There is such thing as harness, but it works only if you throw your DI container into garbage can or write a ton of adapters.
How do one can use InMemory and combine it to completely uncompatible Uri in Send method?
i am new to integration tests. I have an xUnit project in my solution which contains one test only.
Here's the definition of my test:
[Fact]
public async Task ShouldCreateUser()
{
// Arrange
var createUserRequest = new CreateUserRequest
{
Login = "testowyLogin",
Password = "testoweHaslo",
FirstName = "testoweImie",
LastName = "testoweNazwisko",
MailAddress = "test#test.pl"
};
var serializedCreateUserRequest = SerializeObject(createUserRequest);
// Act
var response = await HttpClient.PostAsync(ApiRoutes.CreateUserAsyncRoute,
serializedCreateUserRequest);
// Assert
response
.StatusCode
.Should()
.Be(HttpStatusCode.OK);
}
And the BaseIntegrationTest class definition:
public abstract class BaseIntegrationTest
{
private const string TestDatabaseName = "TestDatabase";
protected BaseIntegrationTest()
{
var appFactory = new WebApplicationFactory<Startup>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
RemoveDatabaseContextFromServicesCollectionIfFound<EventStoreContext>(services);
RemoveDatabaseContextFromServicesCollectionIfFound<GrantContext>(services);
services
.AddDbContext<EventStoreContext>(options =>
options.UseInMemoryDatabase(TestDatabaseName))
.AddDbContext<GrantContext>(options =>
options.UseInMemoryDatabase(TestDatabaseName));
});
});
HttpClient = appFactory.CreateClient();
}
protected HttpClient HttpClient { get; }
protected static StringContent SerializeObject(object #object) =>
new StringContent(
JsonConvert.SerializeObject(#object),
Encoding.UTF8,
"application/json");
private static void RemoveDatabaseContextFromServicesCollectionIfFound<T>(IServiceCollection services)
where T : DbContext
{
var descriptor = services.SingleOrDefault(service =>
service.ServiceType == typeof(DbContextOptions<T>));
if (!(descriptor is null))
{
services
.Remove(descriptor);
}
}
}
When i run tests, it takes few seconds, and the test ends successfully. The problem is that Resharper Test Runner still runs, although i've already have collected results. what am i doing wrong here? Do i have to somehow dispose the HttpClient, after performing all tests? If so, how to achieve that? Thanks for any help.
It looks like you're actually booting the application inside the test rather than using the testhost (https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1)
public class BasicTests
: IClassFixture<WebApplicationFactory<RazorPagesProject.Startup>>
{
private readonly WebApplicationFactory<RazorPagesProject.Startup> _factory;
public BasicTests(WebApplicationFactory<RazorPagesProject.Startup> factory)
{
_factory = factory;
}
[Theory]
[InlineData("/")]
[InlineData("/Index")]
[InlineData("/About")]
[InlineData("/Privacy")]
[InlineData("/Contact")]
public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
{
// Arrange
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync(url);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
Notice the IClassFixture stuff.
In my .Net Core 3.0 app I want to use the Microsoft Graph Nuget library. I have created a connection class that authenticates my application using [MSAL][1] and then creates the connection and returns this. My idea was to inject this connection object in the constructor using Dependency Injection. However, since the method that creates the connection is async, I seem to have a problem how to use it in the constructor.
My Connect Class
public class AuthorizeGraphApi: IAuthorizeGraphApi
{
private readonly IConfiguration _config;
public AuthorizeGraphApi(IConfiguration config)
{
_config = config;
}
public async Task<GraphServiceClient> ConnectToAAD()
{
string accessToken = await GetAccessTokenFromAuthorityAsync();
var graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) => {
requestMessage
.Headers
.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
return Task.FromResult(0);
}));
return graphServiceClient;
}
private async Task<string> GetAccessTokenFromAuthorityAsync()
{
// clientid, authUri, etc removed for this example.
IConfidentialClientApplication _conn;
_conn = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authUri))
.Build();
string[] scopes = new string[] { $"api://{clientId}/.default" };
AuthenticationResult result = null;
// AcquireTokenForClient only has async method.
result = await _conn.AcquireTokenForClient(scopes)
.ExecuteAsync();
return result.AccessToken;
}
}
My Graph Service to send requests
public class AzureIntuneService
{
private readonly IAuthorizeGraphApi _graphClient;
public AzureIntuneService(IAuthorizeGraphApi client)
{
//Gives: cannot implicitely convert to Threading.Tasks.Task.... error
_graphClient = client.ConnectToAAD();
}
public async Task<IList<string>> GetAADInformationAsync()
{
// then here, use the graphClient object for the request...
var payload = await _graphClient.Groups.Request().GetAsync();
return payload
}
}
I register the above classess in my startup as follows:
services.AddScoped<IAuthorizeGraphApi, AuthorizeGraphApi>();
The idea was that this way, I don't need to call the _graphClient in each method. How can I inject the connection object in a correct way? Or what are the best practices regarding this (injecting connection objects)?
One way would be to store a reference to the Task and make sure any public methods that use the connection are async:
public class AzureIntuneService
{
private readonly Task<GraphServiceClient> _graphClientTask;
public AzureIntuneService(IAuthorizeGraphApi client)
{
_graphClientTask = client.ConnectToAAD();
}
public async Task<IList<string>> GetAADInformationAsync()
{
var client = await _graphClientTask; // Get the client when connected
var payload = await client.Groups.Request().GetAsync();
return payload;
}
}
Constructors aren't async and should never be used to initialize anything async. The only way to workaround it is to do sync-over-async by doing a .Result which is always a problem.
In your case, the GraphServiceClient that takes in DelegateAuthenticationProvider, accepts an AuthenticateRequestAsyncDelegate. This allows you to have an async delegate to construct the client.
So now you can do
new DelegateAuthenticationProvider(async requestMessage =>
{
string accessToken = await GetAccessTokenFromAuthorityAsync();
//rest of code here
}
)
and this allows you to change your ConnectToAAD signature to just return a GraphServiceClient and not a Task<GraphServiceClient>.
When you need async data you have to look away from the regular constructor and create a factory method (private static function). Something like below:
public sealed class MyClass
{
private MyData asyncData;
private MyClass() { ... }
private async Task<MyClass> InitializeAsync()
{
asyncData = await GetDataAsync();
return this;
}
public static Task<MyClass> CreateAsync()
{
var ret = new MyClass();
return ret.InitializeAsync();
}
}
public static async Task UseMyClassAsync()
{
MyClass instance = await MyClass.CreateAsync();
...
}
More here: https://blog.stephencleary.com/2013/01/async-oop-2-constructors.html
I have a simple wrapper for stackexchange redis:
public interface IRedisClient
{
Task<RedisResult> ScriptEvaluate(LuaScript script, object parameters);
}
I have a method that calls ScriptEvaluate
public class Foo
{
private readonly IRedisClient _client;
public Foo(IRedisClient client)
{
_client = client;
}
public void RunScript()
{
_client.ScriptEvaluate(LuaScript.Prepare(""), new object());
}
}
Now when I use NSubstitute to mock IRedisClient that is injected to Foo and then call RunScript
public void Test()
{
_foo = new Foo(Substitute.For<IRedisClient>());
_foo.RunScript();
}
I get the following error:
System.TypeLoadException: Method 'AsBoolean' in type
'Castle.Proxies.RedisResultProxy' from assembly
'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=a621a9e7e5c32e69' does not have an implementation.
As far as I can see Nsubstitute/Castle internals do not manage to work with RedisResult properly. I did not manage to find out any workarounds.
Is it possible to do something with this?
P.S. I get the same error when I try to configure the mock to return a value (same exception):
_client
.ScriptEvaluate(null, null)
.ReturnsForAnyArgs(RedisResult.Create((RedisKey)"result"));
I was curious about why mocking the abstract RedisResult was not a simple solution.
This appears to be an issue with NSubstitute's implementation.
Using the following to try and recreate the problem
public class Foo {
private readonly IRedisClient _client;
public Foo(IRedisClient client) {
_client = client;
}
public Task<RedisResult> RunScript() {
return _client.ScriptEvaluate(LuaScript.Prepare(""), new object());
}
}
I was able to reproduce it using NSubstitute but was able to exercise the test to completion when using another mocking framework (MOQ)
[TestClass]
public class MyTestClass {
[TestMethod]
public async Task Test1() {
//Arrange
var expected = RedisResult.Create((RedisKey)"result");
var _client = Substitute.For<IRedisClient>();
_client
.ScriptEvaluate(Arg.Any<LuaScript>(), Arg.Any<object>())
.Returns(expected);
var _foo = new Foo(_client);
//Act
var actual = await _foo.RunScript();
//Assert
actual.Should().Be(expected);
}
[TestMethod]
public async Task Test2() {
//Arrange
var expected = RedisResult.Create((RedisKey)"result");
var _client = Mock.Of<IRedisClient>(_ => _.ScriptEvaluate(It.IsAny<LuaScript>(), It.IsAny<object>()) == Task.FromResult(expected));
var _foo = new Foo(_client);
//Act
var actual = await _foo.RunScript();
//Assert
actual.Should().Be(expected);
}
}
RedisResult is an abstract type, but there are static Create methods for common scenarios, and a few static properties such as EmptyArray, NullArray, etc. I can't tell you how to configure your particular faking layer, but ultimately, I'd expect something involving RedisResult.Create
I am having issues with testing Login Controller using IdentityServer4. It throws the following error:
{System.Net.Http.WinHttpException (0x80072EFD): A connection with the server could not be established
I am trying to generate the access Token using ResourceOwnerPassword, for which I have implemented IResourceOwnerPasswordValidator. I get the error in UserAccessToken.cs class when I call the RequestResourcePasswordAsync.
I am pretty sure it is because of the handler. Because if I use a handler in my test class and call the TokenClient with that handler I do get access Token but then I cannot test my Login Controller.
LoginController.cs
[HttpPost]
public async Task<IActionResult> Login([FromBody]LoginViewModel user)
{
var accessToken = await UserAccessToken.GenerateTokenAsync(user.Username, user.Password);
var loginToken = JsonConvert.DeserializeObject(accessToken);
return Ok(loginToken);
}
UserAccessToken.cs
public async Task<string> GenerateTokenAsync(string username, string password)
{
var tokenUrl = "http://localhost:5000/connect/token";
var tokenClient = new TokenClient(tokenUrl,"ClientId","ClientPassword");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync(username, password, SecurityConfig.PublicApiResourceId);
if (tokenResponse.IsError)
{
throw new AuthenticationFailedException(tokenResponse.Error);
}
return tokenResponse.Json.ToString();
}
TestClass.cs
[Fact]
public async Task Login()
{
var client = _identityServer.CreateClient();
var data = new StringContent(JsonConvert.SerializeObject(new LoginViewModel { Username = "1206", Password = "5m{F?Hk92/Qj}n7Lp6" }), Encoding.UTF8, "application/json");
var dd = await client.PostAsync("http://localhost:5000/login", data);
var ss = dd;
}
IdentityServerSetup.cs //Integration Test Setup
public class IdentityServerSetup
{
private TestServer _identityServer;
private const string TokenEndpoint = "http://localhost:5000/connect/token";
public HttpMessageHandler _handler;
//IF I use this code I do get a AccessToken
public async Task<string> GetAccessTokenForUser(string userName, string password, string clientId, string clientSecret, string apiName = "integrapay.api.public")
{
var client = new TokenClient(TokenEndpoint, clientId, clientSecret, innerHttpMessageHandler: _handler);
var response = await client.RequestResourceOwnerPasswordAsync(userName, password, apiName);
return response.AccessToken;
}
}
Well, you have already answered the question yourself: The problem is with the HttpHandler the TokenClient uses. It should use the one provided by the TestServer to successfully communicate with it instead of doing actual requests to localhost.
Right now, UserAccessToken requires a TokenClient. This is a dependency of your class, so you should refactor the code to pass in a TokenClient instead of generating it yourself. This pattern is called Dependency Injection and is ideal for cases like yours, where you might have different requirements in your tests than in your production setup.
You could make the code look like this:
UserAccessToken.cs
public class UserAccessToken
{
private readonly TokenClient _tokenClient;
public UserAccessToken(TokenClient tokenClient)
{
_tokenClient = tokenClient;
}
public async Task<string> GenerateTokenAsync(string username, string password)
{
var tokenUrl = "http://localhost:5000/connect/token";
var tokenResponse = await _tokenClient.RequestResourceOwnerPasswordAsync(username, password, SecurityConfig.PublicApiResourceId);
if (tokenResponse.IsError)
{
throw new AuthenticationFailedException(tokenResponse.Error);
}
return tokenResponse.Json.ToString();
}
}
TestHelpers.cs
public static class TestHelpers
{
private static TestServer _testServer;
private static readonly object _initializationLock = new object();
public static TestServer GetTestServer()
{
if (_testServer == null)
{
InitializeTestServer();
}
return _testServer;
}
private static void InitializeTestServer()
{
lock (_initializationLock)
{
if (_testServer != null)
{
return;
}
var webHostBuilder = new WebHostBuilder()
.UseStartup<IntegrationTestsStartup>();
var testServer = new TestServer(webHostBuilder);
var initializationTask = InitializeDatabase(testServer);
initializationTask.ConfigureAwait(false);
initializationTask.Wait();
testServer.BaseAddress = new Uri("http://localhost");
_testServer = testServer;
}
}
}
IntegrationTestsStartup.cs
public class IntegrationTestsStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<TokenClient>(() =>
{
var handler = TestUtilities.GetTestServer().CreateHandler();
var client = new TokenClient(TokenEndpoint, clientId, clientSecret, innerHttpMessageHandler: handler);
return client;
};
services.AddTransient<UserAccessToken>();
}
}
LoginController.cs
public class LoginController : Controller
{
private readonly UserAccessToken _userAccessToken;
public LoginController(UserAccessToken userAccessToken)
{
_userAccessToken = userAccessToken;
}
[HttpPost]
public async Task<IActionResult> Login([FromBody]LoginViewModel user)
{
var accessToken = await _userAccessToken .GenerateTokenAsync(user.Username, user.Password);
var loginToken = JsonConvert.DeserializeObject(accessToken);
return Ok(loginToken);
}
}
Here's one of my GitHub projects that makes use of the TestServer class and shows how I'm using it. It's not using IdentityServer4, though.