I have a unit test to check null
parameter. The test method is something like this:
[TestMethod]
public async Task Test_NullParam()
{
Mock<IAuth> mockAuth = new Mock<IAuth>();
Task<AuthenticationResult> mockResult = null;
await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () =>
{
mockAuth
.Setup(x => x.Authenticate(null, param2, param3, param4))
.Returns(mockResult);
});
}
It is showing error under (async ()
.
The error is:
The async lacks await operator
mockResult
showing:
Result is always null
** Edited **
Class code below:
public async Task<AuthenticationResult> Authenticate(string param1, string param2, string param3, string param4)
{
try
{
var authContext = new AuthenticationContext(param1);
if (authContext.TokenCache.ReadItems().Any()) authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
var authResult = await
authContext.AcquireTokenAsync(param2, param3, new Uri(param4), new PlatformParameters(PromptBehavior.Auto, false));
return authResult;
}
catch (Exception)
{
return null;
}
}
You are getting the error because you aren't performing an await
statement in the lambda you've passed to ThrowsExceptionAsync
.
More importantly, you appear to be performing your mocking setup within the lambda instead of actually executing the method that you are testing. You should move your mocking outside of the lambda, and execute the method you are testing within the lambda like this:
[TestMethod]
public async Task Test_NullParam()
{
// create all of your mocks that are required to run this test
Mock<IAuth> mockAuth = new Mock<IAuth>();
Task<AuthenticationResult> mockResult = null;
mockAuth
.Setup(x => x.Authenticate(null, param2, param3, param4))
.Returns(mockResult);
// you actually need to create the concrete type you want to test
// you shouldn't make a unit test that just uses mocks!
// construct the concrete type and pass in any mocks that the
// object requires
var objectToTest = new MyRealObject(mockAuth.Object);
await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () =>
{
// actually execute the real method here, the assertion
// is expecting this method to throw an exception, and will
// only pass if an exception is thrown
await objectToTest.MyMethodAsync();
});
}
Note that if the method you are testing isn't asynchronous, you should change your unit test to not be async, and use Assert.ThrowsException
instead.
Edit:
In response to your comment about mocking the Task
, if you want to mock a Task
that returns a null
AuthenticationResult
, you should do the following:
// declare the result
AuthenticationResult mockResult = null;
// set up the authenticate method to return the task
mockAuth
.Setup(x => x.Authenticate(null, param2, param3, param4))
.Returns(Task.FromResult(mockResult));
The important part here is Task.FromResult
. This will give you an actual Task
, that will return null
when awaited, instead of the Task
being null
itself.
If you want to use an AuthenticationResult
that isn't null, you are going to run into problems, due to the AuthenticationResult
class having no public constructors, and no way of getting one, other than actually running a real Authenticate request. Out of the box, AuthenticationResult
isn't mockable, which is why @Nkosi has provided a link to an article about using wrapper classes to make it mockable .
Edit 2
It seems the linked blog post is not complete, as it does not include all the wrapper types required, so I decided to make them myself so this answer could be complete.
Due to the character limit constraints on StackOverflow answers, I've had to put the files on Github here: https://github.com/DoctaJonez/DoctorJones.IdentityModel.Clients.ActiveDirectory/tree/master
Once you've added these classes and interfaces, you'll be able to do the following:
// you can now mock authentication results, and set them up to
// emulate whatever conditions you like
var mockResult = new Mock<IAuthenticationResultWrapper>();
// you'll need to use the IAuthenticationContextWrapper, so all the
// method signatures know about our new IAuthenticationResultWrapper
var mockAuth = new Mock<IAuthenticationContextWrapper>();
// here's how we mock the IAuthenticationContextWrapper to return our
// mocked IAuthenticationResultWrapper
mockAuth.Setup(x => x.Authenticate(null, param2, param3, param4))
.Returns(Task.FromResult(mockResult.Object));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.