Плотное соединение с HttpClient
в базовом контроллере затрудняет тестирование производных классов изолированно. Просмотрите и реорганизуйте этот код в соответствии с DI.
Нет необходимости иметь базовый контроллер, и обычно это не рекомендуется.
Извлечение PostRequestAsync
в собственную абстракцию и реализацию сервиса.
public interface IWebService {
Task<T> PostRequestAsync<T>(string endpoint, Object obj) where T : class;
Task<T> GetRequestAsync<T>(string endpoint) where T : class;
}
public class WebService : IWebService {
static HttpClient client = new HttpClient();
public virtual async Task<T> PostRequestAsync<T>(string requestUri, Object obj) where T : class {
var content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "");
try {
var response = await client.PostAsync(requestUri, content); // Test case fails here
if (response.IsSuccessStatusCode) {
string data = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(data);
}
return default(T);
} catch (WebException) {
throw;
}
}
public async Task<T> GetRequestAsync<T>(string requestUri) where T : class {
try {
var response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode) {
string data = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(data);
}
return default(T);
} catch (WebException) {
throw;
}
}
}
Рефакторизация производных контроллеров в зависимости от сервисной абстракции
public class AccountController : Controller {
private readonly IWebService webService;
public AccountController(IWebService webService) {
this.webService = webService;
}
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null) {
if (ModelState.IsValid) {
var result = await webService.PostRequestAsync<ResultObject>(Constants.UserLoginAPI, model);
if (result.Succeeded) {
var output = JsonConvert.DeserializeObject<UserObject>(result.Object.ToString());
if (output != null && !string.IsNullOrEmpty(output.Email)) {
var userRoleInfo = await webService.GetRequestAsync<List<UserRoleObject>>(string.Format(Constants.GetUserRoleInfoAPI, output.Email));
if (userRoleInfo != null) {
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, output.Email),
new Claim("Username", output.UserName)
};
var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), new AuthenticationProperties { IsPersistent = model.RememberMe });
}
return View(new LoginViewModel());
}
}
}
return View(model);
}
}
Теперь это должно позволить вам смоделировать зависимость при тестировании в изоляции без неблагоприятных побочных эффектов.
[Fact]
public async Task LoginTest_Post_UserHasInValidCredentials() {
// Arrange
var mockModel = new LoginViewModel { };
mockModel.Password = "TestPassword";
mockModel.Email = "test@test.com";
mockModel.RememberMe = false;
var commonResult = new CommonResult {
Object = null,
Succeeded = false,
StatusCode = Common.Enums.ResponseStatusCodeEnum.Success
};
var mockWebService = new Mock<IWebService>();
var accountController = new AccountController(mockWebService.Object) {
//HttpContext would also be needed
};
mockWebService
.Setup(test => test.PostRequestAsync<CommonResult>(Constants.UserLoginAPI, mockModel))
.ReturnsAsync(commonResult);
//
//Act
var result = await accountController.Login(mockModel);
//Assert
//...Make assertions here
}