У вас есть путь ко многим зависимостям.
Почему сигнатура метода передает значение oauth
, которое никогда не используется?
Прежде всего, вызываялюбая внешняя зависимость через http внутри контроллера должна быть осуждена.Все это должно быть абстрагировано в собственный вызов.Поскольку кажется, что он получает данные, это должно быть на вашем уровне данных.Покрытие целого n-уровневого подхода отдельными проектами, скорее всего, выходит за рамки, поэтому давайте просто охватим необходимый минимум для модульного тестирования , на мой взгляд .
Сначала необходимо абстрагировать ваш HttpClient,На самом деле вы не можете использовать методы модульного тестирования, если они делают какие-либо вызовы вне себя (по большей части), потому что тогда это не модульный тест, а интеграционный тест.
// I don't have a full grasp of your complete eco-system so based on the
// minimal information provided, this would at least get you close
public interface IAzureAPI
{
public Task<string> GetOrgAsync(string org, string oauth);
}
public class AzureAPI : IDisposable
{
public async Task<string> GetOrgAsync(string org, string oauth)
{
// use *using* not try/catch/finally/dispose
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", oauth);
var url = "https://dev.azure.com/" + org+ "/_apis/projects?api-version=4.1";
var response = await client.GetAsync(url);
// never use `.Result` unless you absolutely know what you are doing
// always using async/wait if possible
var result = await response.Content.ReadAsStringAsync();
return result;
}
}
}
Надеюсь, вы используете DIFramework:
public class MyController
{
private IAzureAPI _azureAPI;
public MyController(IAzureAPI azureAPI)
{
_azureAPI = azureAPI;
}
}
Теперь перейдем к сложной части:
public async Task<ActionResult> Organization(string selectedOrg, string oauth)
{
IndexViewModel model = new IndexViewModel();
// I have no idea where model came from so
// this appears to block "unit-testing"
// strange that you don't validate `selectedOrg`, you just use it
model.Organizations = OrganizationData.Data;
if (selectedOrg == null)
{
selectedOrg = model.Organizations.FirstOrDefault().OrgName;
}
else
{
model.SelectedOrg = selectedOrg;
}
// no idea where `_cache` came from so
// also appears to block "unit-testing"
// As does `HttpContext` because you aren't using the
// Interface
var token = _cache.Get<TokenModel>("Token" + HttpContext.Session.GetString("TokenGuid"));
oauth = token.AccessToken;
try
{
var orgInfo = await _azureAPI.GetOrgAsync(selectedOrg, oauth);
model.Projects = JsonConvert.DeserializeObject<ProjectsModel>(orgInfo);
// return a view here???
return View("Index", model);
}
catch(Exception e)
{
// return JSON here instead????
return Json(Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(e.ToString()));
}
}
Это общее начало, но слишком много неизвестных и многих зависимостей, чтобы фактически написать реальный модульный тест.Вот краткая структура и полу-тест, основанный на предоставленной вами информации.
public MyControllerTests
{
// for 100% Cover Coverage you'd need all of these
public async Task Organization_OrgAsString_ReturnsView
{
//...
}
public async Task Organization_OrgAsNull_ReturnsView
{
// Arrange
var azureAPI = Substitute.For<IAzureAPI>();
azureAPI.GetOrgAsync(null, null)
.Returns("somestring");
var controller = new MyController(azureAPI);
// Act
var result = await controller.Organization(null, null);
// Assert
Assert.That(result....);
}
public async Task Organization_WithException_ReturnsJson
{
//...
}
}