Unit testing Armeria's decorator using context.log().whenComplete() - armeria

I have a subclass of SimpleDecoratingHttpService that contains something like this:
override fun serve(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse {
ctx.log().whenComplete().thenAccept {
if (it.responseCause() == ...) {
// do stuff
}
}
return unwrap().serve(ctx, req)
}
I want to test the logic inside the whenComplete() callback. However, when writing tests like this:
myDecorator.serve(context, request).aggregate().join()
the log() future never completes. What do I need to do to ensure that the log() future eventually completes?

Emulating RequestLog completion
A RequestLog is completed by Armeria's networking layer, so just consuming an HttpRequest or HttpResponse will not complete a RequestLog. To complete it, you need to call the methods in RequestLogBuilder:
var myDecorator = new MySimpleDecoratingHttpService(...);
var ctx = ServiceRequestContext.of(
HttpRequest.of(HttpMethod.GET, "/hello"));
var req = ctx.request();
var res = myDecorator.serve(ctx, ctx.req).aggregate().join();
// Fill the log.
ctx.logBuilder().endRequest();
assert ctx.log().isRequestComplete();
ctx.logBuilder().responseHeaders(ResponseHeaders.of(200));
ctx.logBuilder().endResponse();
assert ctx.log().isComplete();
Armeria team uses the same technique for testing BraveService, so you might want to check it out as well at BraveServiceTest.java:161.
Testing with a real server
If your setup is too complex to use a mock, as an alternative approach, you can launch a real Armeria server so that Armeria fills the log for you. You can easily launch a server using ServerRule (JUnit 4) or ServerExtension (JUnit 5):
class MyJUnit5Test {
static final var serviceContexts =
new LinkedBlockingQueue<ServiceRequestContext>();
#RegisterExtension
static final var server = new ServerExtension() {
#Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/hello", (ctx, req) -> HttpResponse.of(200));
sb.decorator(delegate -> new MySimpleDecoratingHttpService(delegate, ...));
// Record the ServiceRequestContext of each request.
sb.decorator((delegate, ctx, req) -> {
serviceContexts.add(ctx);
return delegate.serve(ctx, req);
});
}
};
#BeforeEach
void clearServiceContexts() {
serviceContexts.clear();
}
#Test
void test() {
// Send a real request.
var client = WebClient.of(server.httpUri());
var res = client.get("/hello").aggregate().join();
// Get the ServiceRequestContext and its log.
var ctx = serviceContexts.take();
var log = sctx.log().whenComplete().join();
// .. check `log` here ..
assertEquals(200, log.responseHeaders().status().code());
}
}

Related

How to test code before a suspended coroutine function

Consider the following example in a view model class:
override fun signInViewSelected(
email: String,
password: String
) {
viewModelScope.launch {
loadingViewState.value = LoadingState.Loading("Loading")
withContext(dispatcher.ioDispatcher) {
authManager.signIn(email, password) // suspend fun signIn(email: String, password: String): Boolean -> makes network call
}
loadingViewState.value = LoadingState.NotLoading
}
}
How could I test this method so that I can verify that I start out in loading state, call the authManager.signIn method, and then end up in the not loading state?
When I had this setup with completion handlers I was able to capture the argument passed to my mock authManager class, and then call that manually to advance the completion, but with coroutines I'm not familiar with how to do the equivalent behavior.
What I'd want is something like this, ideally:
#Test
fun `sign in loading state`() {
signInViewModel.signInViewSelected("email#email.com", "password")
val inProgressLoadingViewState = signInViewModel.loadingViewState.getOrAwaitValue()
assertLoadingStateIsLoading(inProgressLoadingViewState, progressMessage)
// delay mockAuthManager until now, have it execute at this point
val finishedLoadingViewState = signInViewModel.loadingViewState.getOrAwaitValue()
assertLoadingStateIsNotLoading(finishedLoadingViewState)
}
Any thoughts?
Assuming you're familiar with libraries like AssertJ and Mockito, I would go about it the following way:
First off, mock the observer of loadingViewState (assuming you have some LiveData in place) and authManager:
private lateinit var viewModel: SomeViewModel
private val loadingViewStateObserver = mock<Observer<LoadingViewState>>()
fun initViewModel() {
viewModel = SomeViewModel().apply {
loadingViewStateLiveData.observeForever(loadingViewStateObserver)
}
}
#Test
fun `sign in loading state`() {
runBlocking {
initViewModel()
viewModel.signInViewSelected("email", "password")
inOrder(loadingViewStateObserver, authManager) {
verify(loadingViewStateObserver).onChanged(LoadingState.NotLoading)
verify(authManager).signIn("email", "password")
verify(loadingViewStateObserver).onChanged(LoadingState.Loading("Loading"))
}
}
}

Verify call to File.Delete with System.IO.Abstractions.TestingHelpers

I use the System.IO.Abstractions.TestingHelpers to mock FileSystem. In my class, I inject IFileSystem and use the instance to call _fileSystem.File.Exists and _fileSystem.File.Delete. In my test class, I would like to verify that the "Delete" method was called. It's easy by mocking only the IFile, but since I already mocked the FileSystem, I don't want to have to mock the Directory, Path and File on top of it. Is it possible to call something like _fileRepository.FileMock.Verify(x => x.Delete(It.IsAny<string>()))...?
public class Downloader : IDownloader
{
public Downloader(HttpClient httpClient, IFileSystem fileSystem)
{
HttpClient = httpClient;
FileSystem = fileSystem;
}
public async Task DownloadConfigFileAsync(string updatedConfigBaseFolderPath, string configurationFileUrl, string personalAccessToken)
{
var newFilePath = FileSystem.Path.Combine(updatedConfigBaseFolderPath, "subfolder1", "myNewFile.txt");
if (FileSystem.File.Exists(newFilePath))
{
FileSystem.File.Delete(newFilePath);
}
// rest of implementation ommited for demo purpose
}
}
And my test is like :
[Fact]
public async void Given_MissingPathParts_ShouldThrow()
{
var handlerMock = GetMessageHandlerMock();
var mockFileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ #"c:\Test\", new MockDirectoryData() },
{ #"c:\Test\subfolder1\myNewFile.txt", new MockFileData(string.Empty) }
});
var httpClient = new HttpClient(handlerMock.Object);
var sut = new Downloader(httpClient, mockFileSystem);
await sut.DownloadConfigFileAsync(BasePath, "http://fakeurl.com?path=%2Fconfiguration%2Flocal%2FTestFile.txt", _fixture.Create<string>());
handlerMock.Protected().Verify(
"SendAsync",
Times.Exactly(1),
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Get),
ItExpr.IsAny<CancellationToken>());
mockFileSystem.File.Exists(FilePath).Should().BeTrue();
// Add assertion that the File.Delete has been called
}
The test freamwork has extensive unit tests itself.
Looking into ...tests\TestableIO.System.IO.Abstractions.TestingHelpers.Tests\MockFileDeleteTests.cs, it just counts the files, which I don't find overly satisying. If there would be a direct way, the creator would have used it.
var fileCount1 = fileSystem.Directory.GetFiles(directory, "*").Length;
fileSystem.File.Delete(path);
var fileCount2 = fileSystem.Directory.GetFiles(directory, "*").Length;
Assert.AreEqual(1, fileCount1, "File should have existed");
Assert.AreEqual(0, fileCount2, "File should have been deleted");

Test CoroutineScope infrastructure in Kotlin

would someone be able to show me how to make the getMovies function in this viewModel testable? I can't get the unit tests to await the coroutines properly..
(1) I'm pretty sure I have to create a test-CoroutineScope and a normal lifeCycle-CoroutineScope, as seen in this Medium Article.
(2) Once the scope definitions are made, I'm also unsure how to tell getMovies() which scope it should be using given a normal app context or a test context.
enum class MovieApiStatus { LOADING, ERROR, DONE }
class MovieListViewModel : ViewModel() {
var pageCount = 1
private val _status = MutableLiveData<MovieApiStatus>()
val status: LiveData<MovieApiStatus>
get() = _status
private val _movieList = MutableLiveData<List<Movie>>()
val movieList: LiveData<List<Movie>>
get() = _movieList
// allows easy update of the value of the MutableLiveData
private var viewModelJob = Job()
// the Coroutine runs using the Main (UI) dispatcher
private val coroutineScope = CoroutineScope(
viewModelJob + Dispatchers.Main
)
init {
Log.d("list", "in init")
getMovies(pageCount)
}
fun getMovies(pageNumber: Int) {
coroutineScope.launch {
val getMoviesDeferred =
MovieApi.retrofitService.getMoviesAsync(page = pageNumber)
try {
_status.value = MovieApiStatus.LOADING
val responseObject = getMoviesDeferred.await()
_status.value = MovieApiStatus.DONE
............
} catch (e: Exception) {
_status.value = MovieApiStatus.ERROR
................
}
}
pageCount = pageNumber.inc()
}
...
}
it uses this API service...
package com.example.themovieapp.network
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import kotlinx.coroutines.Deferred
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
private const val BASE_URL = "https://api.themoviedb.org/3/"
private const val API_key = ""
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.baseUrl(BASE_URL)
.build()
interface MovieApiService{
//https://developers.themoviedb.org/3/movies/get-top-rated-movies
//https://square.github.io/retrofit/2.x/retrofit/index.html?retrofit2/http/Query.html
#GET("movie/top_rated")
fun getMoviesAsync(
#Query("api_key") apiKey: String = API_key,
#Query("language") language: String = "en-US",
#Query("page") page: Int
): Deferred<ResponseObject>
}
/*
Because this call is expensive, and the app only needs
one Retrofit service instance, you expose the service to the rest of the app using
a public object called MovieApi, and lazily initialize the Retrofit service there
*/
object MovieApi {
val retrofitService: MovieApiService by lazy {
retrofit.create(MovieApiService::class.java)
}
}
I'm simply trying to create a test which asserts the liveData 'status' is DONE after the function.
Here is the Project Repository
First you need to make your coroutine scope injectable somehow, either by creating a provider for it manually, or using an injection framework like dagger. That way, when you test your ViewModel, you can override the coroutine scope with a test version.
There are a few choices to do this, you can simply make the ViewModel itself injectable (article on that here: https://medium.com/chili-labs/android-viewmodel-injection-with-dagger-f0061d3402ff)
Or you can manually create a ViewModel provider and use that where ever it's created. No matter what, I would strongly advise some form of dependency injection in order to achieve real testability.
Regardless, your ViewModel needs to have its CoroutineScope provided, not instantiate the coroutine scope itself.
In other words you might want
class MovieListViewModel(val couroutineScope: YourCoroutineScope) : ViewModel() {}
or maybe
class MovieListViewModel #Inject constructor(val coroutineScope: YourCoroutineScope) : ViewModel() {}
No matter what you do for injection, the next step is to create your own CoroutineScope interface that you can override in the test context. For example:
interface YourCoroutineScope : CoroutineScope {
fun launch(block: suspend CoroutineScope.() -> Unit): Job
}
That way when you use the scope for your app, you can use one scope, say, lifecycle coroutine scope:
class LifecycleManagedCoroutineScope(
private val lifecycleCoroutineScope: LifecycleCoroutineScope,
override val coroutineContext: CoroutineContext = lifecycleCoroutineScope.coroutineContext) : YourCoroutineScope {
override fun launch(block: suspend CoroutineScope.() -> Unit): Job = lifecycleCoroutineScope.launchWhenStarted(block)
}
And for your test, you can use a test scope:
class TestScope(override val coroutineContext: CoroutineContext) : YourCoroutineScope {
val scope = TestCoroutineScope(coroutineContext)
override fun launch(block: suspend CoroutineScope.() -> Unit): Job {
return scope.launch {
block.invoke(this)
}
}
}
Now, since your ViewModel is using a scope of type YourCoroutineScope, and since, in the examples above, both the lifecycle and test version implement the YourCoroutineScope interface, you can use different versions of the scope in different situations, i.e. app vs test.
Ok, thanks to Dapp's answer, I was able to write some tests which seem to be awaiting the function Properly.
Here is a copy of what I did :)
enum class MovieApiStatus { LOADING, ERROR, DONE }
class MovieListViewModel(val coroutineScope: ManagedCoroutineScope) : ViewModel() {
//....creating vars, livedata etc.
init {
getMovies(pageCount)
}
fun getMovies(pageNumber: Int) =
coroutineScope.launch{
val getMoviesDeferred =
MovieApi.retrofitService.getMoviesAsync(page = pageNumber)
try {
_status.value = MovieApiStatus.LOADING
val responseObject = getMoviesDeferred.await()
_status.value = MovieApiStatus.DONE
if (_movieList.value == null) {
_movieList.value = ArrayList()
}
pageCount = pageNumber.inc()
_movieList.value = movieList.value!!.toList().plus(responseObject.results)
.sortedByDescending { it.vote_average }
} catch (e: Exception) {
_status.value = MovieApiStatus.ERROR
_movieList.value = ArrayList()
}
}
fun onLoadMoreMoviesClicked() =
getMovies(pageCount)
//...nav functions, clearing functions etc.
}
and here are the test cases
#ExperimentalCoroutinesApi
#RunWith(MockitoJUnitRunner::class)
class MovieListViewModelTest {
#get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
private val testDispatcher = TestCoroutineDispatcher()
private val managedCoroutineScope: ManagedCoroutineScope = TestScope(testDispatcher)
lateinit var viewModel: MovieListViewModel
#Before
fun setup() {
//resProvider.mockColors()
Dispatchers.setMain(testDispatcher)
viewModel = MovieListViewModel(managedCoroutineScope)
}
#After
fun tearDown() {
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
#ExperimentalCoroutinesApi
#Test
fun getMoviesTest() {
managedCoroutineScope.launch {
assertTrue(
"initial List, API status: ${viewModel.status.getOrAwaitValue()}",
viewModel.status.getOrAwaitValue() == MovieApiStatus.DONE
)
assertTrue(
"movieList has ${viewModel.movieList.value?.size}, != 20",
viewModel.movieList.value?.size == 20
)
assertTrue(
"pageCount = ${viewModel.pageCount}, != 2",
viewModel.pageCount == 2
)
viewModel.onLoadMoreMoviesClicked()
assertTrue(
"added to list, API status: ${viewModel.status.getOrAwaitValue()}",
viewModel.status.getOrAwaitValue() == MovieApiStatus.DONE
)
assertTrue(
"movieList has ${viewModel.movieList.value?.size}, != 40",
viewModel.movieList.value?.size == 40
)
}
}
}
It took some trial and error playing around with the Scopes.. runBlockingTest{} was causing an issue 'Exception: job() not completed'..
I also had to create a viewModel factory in order for the fragment to create the viewModel for when the app is running normally..
Project Repo

How to write unit test for ActionFilter when using Service Locator

I am planning to write an ActionFilter for business validation and in which some services will be resolved via Service Locator(I know this is not good practice and as far as possible i avoid Service Locator pattern, but for this case i want to use it).
OnActionExecuting method of the filter is something like this:
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
// get validator for input;
var validator = actionContext.HttpContext.RequestServices.GetService<IValidator<TypeOfInput>>();// i will ask another question for this line
if(!validator.IsValid(input))
{
//send errors
}
}
Is it possible to write unit test for above ActionFilterand how?
Here is an sample on how to create a mock (using XUnit and Moq framework) to verify that the IsValid method is called and where the mock returns an false.
using Dealz.Common.Web.Tests.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using System;
using Xunit;
namespace Dealz.Common.Web.Tests.ActionFilters
{
public class TestActionFilter
{
[Fact]
public void ActionFilterTest()
{
/****************
* Setup
****************/
// Create the userValidatorMock
var userValidatorMock = new Mock<IValidator<User>>();
userValidatorMock.Setup(validator => validator
// For any parameter passed to IsValid
.IsValid(It.IsAny<User>())
)
// return false when IsValid is called
.Returns(false)
// Make sure that `IsValid` is being called at least once or throw error
.Verifiable();
// If provider.GetService(typeof(IValidator<User>)) gets called,
// IValidator<User> mock will be returned
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock.Setup(provider => provider.GetService(typeof(IValidator<User>)))
.Returns(userValidatorMock.Object);
// Mock the HttpContext to return a mockable
var httpContextMock = new Mock<HttpContext>();
httpContextMock.SetupGet(context => context.RequestServices)
.Returns(serviceProviderMock.Object);
var actionExecutingContext = HttpContextUtils.MockedActionExecutingContext(httpContextMock.Object, null);
/****************
* Act
****************/
var userValidator = new ValidationActionFilter<User>();
userValidator.OnActionExecuting(actionExecutingContext);
/****************
* Verify
****************/
// Make sure that IsValid is being called at least once, otherwise this throws an exception. This is a behavior test
userValidatorMock.Verify();
// TODO: Also Mock HttpContext.Response and return in it's Body proeprty a memory stream where
// your ActionFilter writes to and validate the input is what you desire.
}
}
class User
{
public string Username { get; set; }
}
class ValidationActionFilter<T> : IActionFilter where T : class, new()
{
public void OnActionExecuted(ActionExecutedContext context)
{
throw new NotImplementedException();
}
public void OnActionExecuting(ActionExecutingContext actionContext)
{
var type = typeof(IValidator<>).MakeGenericType(typeof(T));
var validator = (IValidator<T>)actionContext.HttpContext
.RequestServices.GetService<IValidator<T>>();
// Get your input somehow
T input = new T();
if (!validator.IsValid(input))
{
//send errors
actionContext.HttpContext.Response.WriteAsync("Error");
}
}
}
internal interface IValidator<T>
{
bool IsValid(T input);
}
}
HttpContextUtils.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Collections.Generic;
namespace Dealz.Common.Web.Tests.Utils
{
public class HttpContextUtils
{
public static ActionExecutingContext MockedActionExecutingContext(
HttpContext context,
IList<IFilterMetadata> filters,
IDictionary<string, object> actionArguments,
object controller
)
{
var actionContext = new ActionContext() { HttpContext = context };
return new ActionExecutingContext(actionContext, filters, actionArguments, controller);
}
public static ActionExecutingContext MockedActionExecutingContext(
HttpContext context,
object controller
)
{
return MockedActionExecutingContext(context, new List<IFilterMetadata>(), new Dictionary<string, object>(), controller);
}
}
}
As you can see, it's quite a mess, you need to create plenty of mocks to simulate different responses of the actuall classes, only to be able to test the ActionAttribute in isolation.
I like #Tseng's above answer but thought of giving one more answer as his answer covers more scenarios (like generics) and could be overwhelming for some users.
Here I have an action filter attribute which just checks the ModelState and short circuits(returns the response without the action being invoked) the request by setting the Result property on the context. Within the filter, I try to use the ServiceLocator pattern to get a logger to log some data(some might not like this but this is an example)
Filter
public class ValidationFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<ValidationFilterAttribute>>();
logger.LogWarning("some message here");
context.Result = new JsonResult(new InvalidData() { Message = "some messgae here" })
{
StatusCode = 400
};
}
}
}
public class InvalidData
{
public string Message { get; set; }
}
Unit Test
[Fact]
public void ValidationFilterAttributeTest_ModelStateErrors_ResultInBadRequestResult()
{
// Arrange
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock
.Setup(serviceProvider => serviceProvider.GetService(typeof(ILogger<ValidationFilterAttribute>)))
.Returns(Mock.Of<ILogger<ValidationFilterAttribute>>());
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = serviceProviderMock.Object;
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var actionExecutingContext = new ActionExecutingContext(
actionContext,
filters: new List<IFilterMetadata>(), // for majority of scenarios you need not worry about populating this parameter
actionArguments: new Dictionary<string, object>(), // if the filter uses this data, add some data to this dictionary
controller: null); // since the filter being tested here does not use the data from this parameter, just provide null
var validationFilter = new ValidationFilterAttribute();
// Act
// Add an erorr into model state on purpose to make it invalid
actionContext.ModelState.AddModelError("Age", "Age cannot be below 18 years.");
validationFilter.OnActionExecuting(actionExecutingContext);
// Assert
var jsonResult = Assert.IsType<JsonResult>(actionExecutingContext.Result);
Assert.Equal(400, jsonResult.StatusCode);
var invalidData = Assert.IsType<InvalidData>(jsonResult.Value);
Assert.Equal("some messgae here", invalidData.Message);
}

Moq - Setup method with complex parameters

I'm trying to set up a mock of this interface:
public interface IAuthenticatedRequestService
{
HttpClient CreateHttpClientForJwt(Func<HttpResponseMessage, bool> isUnauthenticated, int timeoutSeconds);
HttpClient CreateHttpClientForAccessToken(Func<HttpResponseMessage, bool> isUnauthenticated, int timeoutSeconds);
}
This is one implementation of the method to setup that is in use and working:
public HttpClient CreateHttpClientForAccessToken(Func<HttpResponseMessage, bool> isUnauthenticated, int timeoutSeconds)
{
var client = Mvx.Resolve<IPlatformOperationProvider>().CreateHttpClient(timeoutSeconds);
return new HttpClient(new AuthenticatedHttpMessageHandler(this, client, AuthenticationUtils.AddAccessTokenToRequest, isUnauthenticated,_loggingService));
}
This is one usage of the implemented method that is working:
var client = service.CreateHttpClientForAccessToken(x => x.StatusCode == HttpStatusCode.Unauthorized, CoreConstants.TimeoutMyDetails);
This is my unit test which sets up the mock:
[Test]
public async void TestIsLoggedInIsTrue()
{
//Arrange
var authenticatedRequestService = new Mock<IAuthenticatedRequestService>();
authenticatedRequestService.Setup(foo => foo.CreateHttpClientForAccessToken((It.IsAny<Func <HttpResponseMessage, bool>>())
, 0
)).Returns(new HttpClient());
var platformOperationProvider = new Mock<IPlatformOperationProvider>();
platformOperationProvider.Setup(foo => foo.CreateHttpClient(1)).Returns(new HttpClient());
Mvx.RegisterSingleton<IPlatformOperationProvider>(platformOperationProvider.Object);
Mvx.RegisterSingleton<IAuthenticatedRequestService>(authenticatedRequestService.Object);
var loggedInProvider = new LoggedInProvider(
new Mock<ISecuredSettings>().Object,
new Mock<ILoggingService>().Object
);
//Act
await loggedInProvider.SetUserAndToken(
new User(),
new ApiAccessInfo("refresh token", "access token", "jwt")
);
//Assert
Assert.IsTrue(loggedInProvider.IsLoggedIn);
}
This unit test has no errors, but the test fails (I think it is because I am passing it any HttpResponseMessage? And I need to somehow pass it HttpStatusCode.Accepted? How would I do that?
Take note of the usage of the method, how it passes HttpStatusCode.Unauthorized, then can I do something like that with HttpStatusCode.Accepted?:
var client = service.CreateHttpClientForAccessToken(x => x.StatusCode == HttpStatusCode.Unauthorized, CoreConstants.TimeoutMyDetails);
EDIT: To be clear, It is this line of code that I need to correct:
authenticatedRequestService.Setup(foo => foo.CreateHttpClientForAccessToken((It.IsAny<Func <HttpResponseMessage, bool>>())
, 0
)).Returns(new HttpClient());
EDIT: Whilst debugging the problem starts here (check the code comment after the client is created):
async Task<ServiceResponse> UpdateUserDetails()
{
// Have to late-resolve this otherwise we end up with a dependency loop
var service = Mvx.Resolve<IAuthenticatedRequestService>();
try
{
var client = service.CreateHttpClientForAccessToken(x => x.StatusCode == HttpStatusCode.Unauthorized, CoreConstants.TimeoutMyDetails);
// here is the problem, the client is null after this line of code.
var user = _user;
I have since found that it is not a Moq issue. MvvmCross is not registering the object to resolve correctly.
This line is not working:
Mvx.RegisterSingleton<IAuthenticatedRequestService>(authenticatedRequestService.Object);
as this line creates an AuthenticatedRequestService but it is not the mock one that I made:
var service = Mvx.Resolve<IAuthenticatedRequestService>();
Here is some context of resolving the AuthenticatedRequestService
async Task<ServiceResponse> UpdateUserDetails()
{
// Have to late-resolve this otherwise we end up with a dependency loop
var service = Mvx.Resolve<IAuthenticatedRequestService>();
try
{
var client = service.CreateHttpClientForAccessToken(x => x.StatusCode == HttpStatusCode.Unauthorized, CoreConstants.TimeoutMyDetails);
var user = _user;
var str = await client.GetStringAsync(new Uri(user.IdUrl));
var newUser = JsonConvert.DeserializeObject<User.Json>(str);
var token = _token;
if (token != null)