C# 如何模拟(MOQ)已密封安装程序AbstractAcquireTokenParameterBuilder的IConfidentialClientApplication?
尝试为C# 如何模拟(MOQ)已密封安装程序AbstractAcquireTokenParameterBuilder的IConfidentialClientApplication?,c#,unit-testing,.net-core,moq,msal,C#,Unit Testing,.net Core,Moq,Msal,尝试为IConfidentialClientApplication设置moq时出现以下异常: System.NotSupportedException:不支持的表达式:…=> ..…ExecuteAsync()不可重写的成员(此处: AbstractAcquireTokenParameterBuilder.ExecuteAsync) 不能在设置/验证表达式中使用 private Mock_appMock=new Mock(); [事实] 公共异步任务GetAccessTokenResultAsy
IConfidentialClientApplication
设置moq时出现以下异常:
System.NotSupportedException:不支持的表达式:…=>
..…ExecuteAsync()不可重写的成员(此处:
AbstractAcquireTokenParameterBuilder.ExecuteAsync)
不能在设置/验证表达式中使用
private Mock_appMock=new Mock();
[事实]
公共异步任务GetAccessTokenResultAsync_with GoodSetup_ReturnsToken()
{
//利用用于测试中模拟的MSAL AuthenticationResult构造函数
var authentication=CreateAuthenticationResult();
//这里抛出异常
_appMock.Setup(\u=>\ u0.AcquireTokenForClient(It.IsAny()).ExecuteAsync())
.ReturnsAsync(身份验证);
…剩下的测试。。。
}
返回一个AcquireTokenForClientParameterBuilder
。AcquireTokenForClient
;“一个生成器,允许您在执行令牌请求之前添加可选参数”,所以我不能轻易地模仿这个棘手的物体
对于那些好奇的人来说,
CreateAuthenticationResult()
是一种从Microsoft.Identity.Client.AuthenticationResult调用签名的方法,Microsoft专门添加了该签名,用于存根AuthenticationResult
,因为它也是一个密封的类,所以不能被模拟
鉴于
AcquireTokenForClientParameterBuilder
是通过外部库提供的,您显然无法将其修改为更易于测试。考虑到这一点,我建议将代码抽象到您自己的接口后面(类似于将适配器模式应用于测试目的)
以以下服务/测试为例,说明您当前如何使用IConfidentialClientApplication并尝试模拟它(这会导致与您看到的相同错误):
公共类MyService
{
私有只读IConfidentialClientApplication _机密客户端应用程序;
公共MyService(IConfidentialClientApplication机密客户端应用程序)
{
_机密客户端应用程序=机密客户端应用程序;
}
公共异步任务GetAccessToken(IEnumerable作用域)
{
AcquireTokenForClientParameterBuilder tokenBuilder=\u机密客户端应用程序。AcquireTokenForClient(作用域);
AuthenticationResult token=等待tokenBuilder.ExecuteAsync();
返回token.AccessToken;
}
}
公共类UnitTest1
{
[事实]
公共异步任务Test1()
{
Mock _appMock=新建Mock();
AuthenticationResult authentication=CreateAuthenticationResult(“myToken”);
_appMock
.Setup(=>u.AcquireTokenForClient(It.IsAny()).ExecuteAsync())
.ReturnsAsync(身份验证);
var myService=newmyservice(_appMock.Object);
string accessToken=wait myService.GetAccessToken(新字符串[]{});
Assert.Equal(“myToken”,accessToken);
}
私有身份验证结果CreateAuthenticationResult(字符串accessToken)=>
新的AuthenticationResult(accessToken、true、null、DateTimeOffset.Now、DateTimeOffset.Now、string.Empty、null、null、null、Guid.Empty);
}
通过引入单独的接口,您的代码可以简单地依赖于此,让您控制如何使用/测试它:
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);
}
}
公共接口IIdentialClientAdapter
{
任务GetAccessToken(IEnumerable作用域);
}
公共类IdentityClientAdapter:IIdentialClientAdapter
{
私有只读IConfidentialClientApplication _机密客户端应用程序;
公共标识客户端适配器(IConfidentialClientApplication机密客户端应用程序)
{
_机密客户端应用程序=机密客户端应用程序;
}
公共异步任务GetAccessToken(IEnumerable作用域)
{
AcquireTokenForClientParameterBuilder tokenBuilder=\u机密客户端应用程序。AcquireTokenForClient(作用域);
AuthenticationResult token=等待tokenBuilder.ExecuteAsync();
返回token.AccessToken;
}
}
公共类MyService
{
专用只读IIdentialClientAdapter_identityClientAdapter;
公共MyService(IIdentialClientAdapter identityClientAdapter)
{
_identityClientAdapter=identityClientAdapter;
}
公共异步任务GetAccessToken(IEnumerable作用域)
{
返回wait_identityClientAdapter.GetAccessToken(作用域);
}
}
公共类UnitTest1
{
[事实]
公共异步任务Test1()
{
Mock _appMock=新建Mock();
_appMock
.Setup(=>u.GetAccessToken(It.IsAny()))
.ReturnsAsync(“myToken”);
var myService=newmyservice(_appMock.Object);
string accessToken=wait myService.GetAccessToken(新字符串[]{});
Assert.Equal(“myToken”,accessToken);
}
}
这个例子显然是微不足道的,但仍然应该适用。接口只需要适合您的需要。您是否可以包含从
AcquireTokenForClient()返回的类型定义。
?似乎需要为该类型创建一个单独的模拟/存根,并让它从ExecuteAsync()
@devNullAcquireTokenForClient()
返回AcquireTokenForClientParameterBuilder
返回身份验证。我更新了我的答案,以便更好地解释这一点。
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);
}
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);
}
}