Keri sisuni

Kontrollerite testimine

Puhtaid kontrollereid, mis tegelevad vastavalt MVC disainimustrile kasutaja ja süsteemi vahelise suhtluse koordineerimisega, on küllaltki lihtne testida. Koordineeriv kood on tavaliselt lakooniline ja kontrollerite aktsioonid pole seega suured.

Kontrollerite testid

Kontrollerite testid paigutame ühiktestide projektis kataloogi ControllerTests. Iga kontrolleri jaoks loome eraldi testide klassi, mis tegeleb just selle konkreetse kontrolleri testimisega. Testide paindlikumaks muutmiseks kasutame mock-raamistiku, et vabaneda sõltuvustest. Mock-objekti ja testitava kontrolleri teeme kättesaadavaks klassi skoobis. Kõige mõistlikum on see töö ära teha testklassi konstruktoris nagu näidatud järgnevas koodilõigus.

public class ProductsControllerTests
{
    private readonly Mock<IProductService> _productServiceMock;
    private readonly ProductsController _productsController;

    public ProductsControllerTests()
    {
        // Loo IProductService jaoks mock
        _productServiceMock = new Mock<IProductService>();

        // Loo kontroller ning anna mocki loodud objekt sellele kaasa
        _productsController = new ProductsController(_productServiceMock.Object);
    }

    // Testid
}

Võtame vaatluse alla tüüpilise Details() aktsiooni, mis on genereeritud Visual Studio abil ning viidud üle teenustele ja mudeliklassidele.

public class ProductsController : Controller
{
    private readonly IProductService _productService;
    private readonly ProductsController _productsController;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    // ...

    public async Task<IActionResult> Details(int? id)
    {
        if(id == null)
        {
            return NotFound();
        }

        var model = await _productService.GetById(id.Value);
        if(model == null)
        {
            return NotFound();
        }

        return View(model)
    }

    // ...
}

Details() aktsioonile saaksime kirjutada mitu testi:

  1. Kas Details() meetod tagastab NotFoundResult kui id on null?
  2. Kas Details() meetod tagastab NotFoundResult kui model on null?
  3. Kas Details() meetod tagastab meile korrektse mudeli ja vaate kui probleeme ei tekkinud?

ProductsControllerTests klass näeks nende kolme testiga välja selline.

public class ProductsControllerTests
{
    private readonly Mock<IProductService> _productServiceMock;
    private readonly ProductsController _productsController;

    public ProductsControllerTests()
    {
        // Loo IProductService jaoks mock
        _productServiceMock = new Mock<IProductService>();

        // Loo kontroller ning anna mocki loodud objekt sellele kaasa
        _productsController = new ProductsController(_productServiceMock.Object);
    }

    [Fact]
    public async Task Details_should_return_notfound_when_id_is_null()
    {
        // Arrange
        var productId = (int?)null;

        // Act
        var result = await _controller.Details(productId) as NotFoundResult;

        // Assert
        Assert.NotNull(result);
    }

    [Fact]
    public async Task Details_should_return_notfound_when_product_is_null()
    {
        // Arrange
        var productId = -1;
        var product = (Product)null;
        _productServiceMock.Setup(ps => ps.GetById(productId))
                           .ReturnsAsync(() => product);

        // Act
        var result = await _controller.Details(productId) as NotFoundResult;

        // Assert
        Assert.NotNull(result);
    }

    [Fact]
    public async Task Details_should_return_correct_view_and_model_when_product_was_found()
    {
        // Arrange
        var productId = 1;
        var product = new Product { Id = productId, Name = "Product 1" };
        var viewNames = new string[] { null, "Details" };
        _productServiceMock.Setup(ps => ps.GetById(productId))
                           .ReturnsAsync(() => product);

        // Act
        var result = await _controller.Details(productId) as ViewResult;

        // Assert
        Assert.NotNull(result);
        Assert.Contains(result.ViewName, viewNames);
        Assert.NotNull(result.Model);
        Assert.Equal(productId, ((Product)result.Model).Id);
    }
}

Mahukamate testiklasside tükeldamine

Viited