Template
327 lines
14 KiB
C#
327 lines
14 KiB
C#
using FluentAssertions;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Moq;
|
|
using NUnit.Framework;
|
|
using Strata.ContinuousImprovement.Api.Controllers;
|
|
using Strata.ContinuousImprovement.Biz.StrategicOpportunities;
|
|
using Strata.ContinuousImprovement.Biz.StrategicOpportunities.Dtos;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Strata.ContinuousImprovement.Api.Test.Unit.Controllers
|
|
{
|
|
[ExcludeFromCodeCoverage]
|
|
[TestFixture, Category("Unit"), Category("Controller")]
|
|
public class StrategicOpportunityControllerTests
|
|
{
|
|
private StrategicOpportunityController _controller;
|
|
private Mock<IStrategicOpportunityService> _mockOpportunityService;
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
_mockOpportunityService = new Mock<IStrategicOpportunityService>();
|
|
_controller = new StrategicOpportunityController(_mockOpportunityService.Object);
|
|
}
|
|
|
|
// --- GetGeneralInfo ---
|
|
|
|
[Test]
|
|
public async Task GetGeneralInfo_ReturnsOk_WhenOpportunityExists()
|
|
{
|
|
const long opportunityId = 1;
|
|
var info = new StrategicOpportunityGeneralInfo();
|
|
_mockOpportunityService
|
|
.Setup(s => s.GetStrategicOpportunityGeneralInfo(opportunityId, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(info);
|
|
|
|
var result = await _controller.GetGeneralInfo(opportunityId, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>()
|
|
.Which.Value.Should().Be(info);
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetGeneralInfo_ReturnsNotFound_WhenOpportunityMissing()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.GetStrategicOpportunityGeneralInfo(It.IsAny<long>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((StrategicOpportunityGeneralInfo)null);
|
|
|
|
var result = await _controller.GetGeneralInfo(99, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<NotFoundResult>();
|
|
}
|
|
|
|
// --- GetDrawerDetails ---
|
|
|
|
[Test]
|
|
public async Task GetDrawerDetails_ReturnsOk_WhenOpportunityExists()
|
|
{
|
|
const long opportunityId = 5;
|
|
var details = new StrategicOpportunityDrawerDetails();
|
|
_mockOpportunityService
|
|
.Setup(s => s.GetStrategicOpportunityDrawerDetails(opportunityId, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(details);
|
|
|
|
var result = await _controller.GetDrawerDetails(opportunityId, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>()
|
|
.Which.Value.Should().Be(details);
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetDrawerDetails_ReturnsNotFound_WhenOpportunityMissing()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.GetStrategicOpportunityDrawerDetails(It.IsAny<long>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((StrategicOpportunityDrawerDetails)null);
|
|
|
|
var result = await _controller.GetDrawerDetails(99, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<NotFoundResult>();
|
|
}
|
|
|
|
// --- Copy ---
|
|
|
|
[Test]
|
|
public async Task Copy_ReturnsOk_WithNewId_WhenSuccessful()
|
|
{
|
|
const long opportunityId = 10;
|
|
const long newId = 42;
|
|
_mockOpportunityService
|
|
.Setup(s => s.CopyStrategicOpportunity(opportunityId, It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(newId);
|
|
|
|
var result = await _controller.Copy(opportunityId, "Copy of Opp", CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>()
|
|
.Which.Value.Should().Be(newId);
|
|
}
|
|
|
|
[Test]
|
|
public async Task Copy_ReturnsBadRequest_WhenServiceReturnsZero()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.CopyStrategicOpportunity(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(0L);
|
|
|
|
var result = await _controller.Copy(10, "Copy of Opp", CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<BadRequestResult>();
|
|
}
|
|
|
|
// --- SetStatus ---
|
|
|
|
[Test]
|
|
public async Task SetStatus_ReturnsOk_WhenUpdateSucceeds()
|
|
{
|
|
const long opportunityId = 3;
|
|
var dto = new StrategicOpportunityUpdateStatusDto();
|
|
_mockOpportunityService
|
|
.Setup(s => s.UpdateStrategicOpportunityStatus(opportunityId, dto, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(true);
|
|
|
|
var result = await _controller.SetStatus(opportunityId, dto, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetStatus_ReturnsNotFound_WhenUpdateFails()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.UpdateStrategicOpportunityStatus(It.IsAny<long>(), It.IsAny<StrategicOpportunityUpdateStatusDto>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(false);
|
|
|
|
var result = await _controller.SetStatus(99, new StrategicOpportunityUpdateStatusDto(), CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<NotFoundResult>();
|
|
}
|
|
|
|
// --- UpdateLayout ---
|
|
|
|
[Test]
|
|
public async Task UpdateLayout_ReturnsOk_WhenUpdateSucceeds()
|
|
{
|
|
const long opportunityId = 7;
|
|
var layout = new StrategicOpportunityLayout();
|
|
_mockOpportunityService
|
|
.Setup(s => s.UpdateStrategicOpportunityLayout(opportunityId, layout, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(true);
|
|
|
|
var result = await _controller.UpdateLayout(opportunityId, layout, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task UpdateLayout_ReturnsNotFound_WhenUpdateFails()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.UpdateStrategicOpportunityLayout(It.IsAny<long>(), It.IsAny<StrategicOpportunityLayout>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(false);
|
|
|
|
var result = await _controller.UpdateLayout(99, new StrategicOpportunityLayout(), CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<NotFoundResult>();
|
|
}
|
|
|
|
// --- UpdateRoles ---
|
|
|
|
[Test]
|
|
public async Task UpdateRoles_ReturnsOk_WhenUpdateSucceeds()
|
|
{
|
|
const long opportunityId = 4;
|
|
var dto = new StrategicRolesUpdate();
|
|
_mockOpportunityService
|
|
.Setup(s => s.UpdateRoles(opportunityId, dto, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(true);
|
|
|
|
var result = await _controller.UpdateRoles(opportunityId, dto, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task UpdateRoles_ReturnsNotFound_WhenUpdateFails()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.UpdateRoles(It.IsAny<long>(), It.IsAny<StrategicRolesUpdate>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(false);
|
|
|
|
var result = await _controller.UpdateRoles(99, new StrategicRolesUpdate(), CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<NotFoundResult>();
|
|
}
|
|
|
|
// --- RunTrackingTask ---
|
|
|
|
[Test]
|
|
public async Task RunTrackingTask_ReturnsOk_WhenSuccessful()
|
|
{
|
|
const long opportunityId = 8;
|
|
_mockOpportunityService
|
|
.Setup(s => s.RunTrackingTask(opportunityId, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(true);
|
|
|
|
var result = await _controller.RunTrackingTask(opportunityId, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task RunTrackingTask_ReturnsNotFound_WhenOpportunityMissing()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.RunTrackingTask(It.IsAny<long>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(false);
|
|
|
|
var result = await _controller.RunTrackingTask(99, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<NotFoundResult>();
|
|
}
|
|
|
|
// --- GetMeasures ---
|
|
|
|
[Test]
|
|
public async Task GetMeasures_ReturnsOk_WhenMeasuresExist()
|
|
{
|
|
const long opportunityId = 2;
|
|
var measures = new List<StrategicOpportunityMeasureDto> { new() };
|
|
_mockOpportunityService
|
|
.Setup(s => s.GetStrategicOpportunityMeasures(opportunityId, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(measures);
|
|
|
|
var result = await _controller.GetMeasures(opportunityId, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>()
|
|
.Which.Value.Should().Be(measures);
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetMeasures_ReturnsNotFound_WhenNoMeasures()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.GetStrategicOpportunityMeasures(It.IsAny<long>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new List<StrategicOpportunityMeasureDto>());
|
|
|
|
var result = await _controller.GetMeasures(99, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<NotFoundResult>();
|
|
}
|
|
|
|
// --- CompleteInitiative ---
|
|
|
|
[Test]
|
|
public async Task CompleteInitiative_ReturnsOk_WhenSuccessful()
|
|
{
|
|
const long opportunityId = 6;
|
|
var data = new StrategicOpportunityCompleteInitiativeData();
|
|
_mockOpportunityService
|
|
.Setup(s => s.CompleteInitiative(opportunityId, data, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(true);
|
|
|
|
var result = await _controller.CompleteInitiative(opportunityId, data, CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<OkObjectResult>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task CompleteInitiative_ReturnsNotFound_WhenOpportunityMissing()
|
|
{
|
|
_mockOpportunityService
|
|
.Setup(s => s.CompleteInitiative(It.IsAny<long>(), It.IsAny<StrategicOpportunityCompleteInitiativeData>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(false);
|
|
|
|
var result = await _controller.CompleteInitiative(99, new StrategicOpportunityCompleteInitiativeData(), CancellationToken.None);
|
|
|
|
result.Result.Should().BeOfType<NotFoundResult>();
|
|
}
|
|
|
|
// --- Route attribute assertions ---
|
|
|
|
[Test]
|
|
public void Controller_HasExpectedRouteTemplate()
|
|
{
|
|
var routeAttr = typeof(StrategicOpportunityController).GetCustomAttribute<RouteAttribute>();
|
|
|
|
routeAttr.Should().NotBeNull();
|
|
routeAttr.Template.Should().Be("api/v{api-version:apiVersion}/[controller]");
|
|
}
|
|
|
|
[TestCase(nameof(StrategicOpportunityController.GetOpportunities), typeof(HttpGetAttribute), "")]
|
|
[TestCase(nameof(StrategicOpportunityController.GetGeneralInfo), typeof(HttpGetAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.IsNameValid), typeof(HttpPostAttribute), "[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.GetLayout), typeof(HttpGetAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.UpdateLayout), typeof(HttpPutAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.SetStatus), typeof(HttpPutAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.GetInitiatives), typeof(HttpGetAttribute), "[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.UpdateInitiative), typeof(HttpPutAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.UpdateRoles), typeof(HttpPutAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.UpdateRampUps), typeof(HttpPutAttribute), "{opportunityId}/ramp-ups")]
|
|
[TestCase(nameof(StrategicOpportunityController.GetRampUps), typeof(HttpGetAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.RunTrackingTask), typeof(HttpGetAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.CompleteInitiative), typeof(HttpPutAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.GetMeasures), typeof(HttpGetAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.GetPrimaryMeasure), typeof(HttpGetAttribute), "{opportunityId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.GetMeasureDetails), typeof(HttpGetAttribute), "{measureId}/[action]")]
|
|
[TestCase(nameof(StrategicOpportunityController.GetDrawerDetails), typeof(HttpGetAttribute), "{opportunityId}")]
|
|
[TestCase(nameof(StrategicOpportunityController.Copy), typeof(HttpPostAttribute), "{opportunityId}/copy")]
|
|
public void ActionRoute_HasExpectedHttpMethodAndTemplate(string methodName, Type httpAttrType, string expectedTemplate)
|
|
{
|
|
var method = typeof(StrategicOpportunityController).GetMethod(methodName);
|
|
method.Should().NotBeNull($"method '{methodName}' should exist on {nameof(StrategicOpportunityController)}");
|
|
|
|
var attr = method.GetCustomAttribute(httpAttrType);
|
|
attr.Should().NotBeNull($"{methodName} should be decorated with [{httpAttrType.Name}]");
|
|
var template = (string)attr.GetType().GetProperty("Template").GetValue(attr);
|
|
template.Should().Be(expectedTemplate);
|
|
}
|
|
}
|
|
}
|