ASP.NET Core'da birim testi denetleyicisi mantığı

Tarafından Steve Smith

Birim testleri , bir uygulamanın bir bölümünü altyapısından ve bağımlılıklarından yalıtılarak test etmeyi içerir. Birim testi denetleyicisi mantığı, bağımlılıklarının veya çerçevenin davranışını değil, yalnızca tek bir eylemin içeriğini test eder.

Birim testi denetleyicileri

Denetleyicinin davranışına odaklanmak için denetleyici eylemlerinin birim testlerini ayarlayın. Denetleyici birim testi filtreler, yönlendirme ve model bağlama gibi senaryoları önler. Bir isteğe toplu olarak yanıt veren bileşenler arasındaki etkileşimleri kapsayan testler tümleştirme testleri tarafından işlenir. Tümleştirme testleri hakkında daha fazla bilgi için bkz . ASP.NET Core'da tümleştirme testleri.

Özel filtreler ve yollar yazıyorsanız, birim testi bunları belirli bir denetleyici eylemindeki testlerin parçası olarak değil yalıtımlı olarak test edin.

Denetleyici birim testlerini göstermek için örnek uygulamada aşağıdaki denetleyiciyi gözden geçirin.

Örnek kodu görüntüleme veya indirme (indirme)

Denetleyici Home , beyin fırtınası oturumlarının listesini görüntüler ve POST isteğiyle yeni beyin fırtınası oturumları oluşturulmasına olanak tanır:

public class HomeController : Controller
{
    private readonly IBrainstormSessionRepository _sessionRepository;

    public HomeController(IBrainstormSessionRepository sessionRepository)
    {
        _sessionRepository = sessionRepository;
    }

    public async Task<IActionResult> Index()
    {
        var sessionList = await _sessionRepository.ListAsync();

        var model = sessionList.Select(session => new StormSessionViewModel()
        {
            Id = session.Id,
            DateCreated = session.DateCreated,
            Name = session.Name,
            IdeaCount = session.Ideas.Count
        });

        return View(model);
    }

    public class NewSessionModel
    {
        [Required]
        public string SessionName { get; set; }
    }

    [HttpPost]
    public async Task<IActionResult> Index(NewSessionModel model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        else
        {
            await _sessionRepository.AddAsync(new BrainstormSession()
            {
                DateCreated = DateTimeOffset.Now,
                Name = model.SessionName
            });
        }

        return RedirectToAction(actionName: nameof(Index));
    }
}

Önceki denetleyici:

  • Açık Bağımlılıklar İlkesi'ni izler.
  • Bağımlılık eklemenin (DI) bir örneğini sağlamasını IBrainstormSessionRepositorybekler.
  • Moq gibi bir sahte IBrainstormSessionRepository nesne çerçevesi kullanılarak sahte bir hizmetle test edilebilir. Sahte nesne, test için kullanılan önceden belirlenmiş bir özellik ve yöntem davranışları kümesine sahip, oluşturulmuş bir nesnedir. Daha fazla bilgi için bkz . Tümleştirme testlerine giriş.

Yöntemin HTTP GET Index döngü veya dallanma yoktur ve yalnızca bir yöntemi çağırır. Bu eylem için birim testi:

  • IBrainstormSessionRepository yöntemini kullanarak hizmetle dalga geçerGetTestSessions. GetTestSessions tarihler ve oturum adları içeren iki sahte beyin fırtınası oturumu oluşturur.
  • yöntemini yürütür Index .
  • yöntemi tarafından döndürülen sonuç üzerinde onaylar yapar:
[Fact]
public async Task Index_ReturnsAViewResult_WithAListOfBrainstormSessions()
{
    // Arrange
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.ListAsync())
        .ReturnsAsync(GetTestSessions());
    var controller = new HomeController(mockRepo.Object);

    // Act
    var result = await controller.Index();

    // Assert
    var viewResult = Assert.IsType<ViewResult>(result);
    var model = Assert.IsAssignableFrom<IEnumerable<StormSessionViewModel>>(
        viewResult.ViewData.Model);
    Assert.Equal(2, model.Count());
}
private List<BrainstormSession> GetTestSessions()
{
    var sessions = new List<BrainstormSession>();
    sessions.Add(new BrainstormSession()
    {
        DateCreated = new DateTime(2016, 7, 2),
        Id = 1,
        Name = "Test One"
    });
    sessions.Add(new BrainstormSession()
    {
        DateCreated = new DateTime(2016, 7, 1),
        Id = 2,
        Name = "Test Two"
    });
    return sessions;
}

Denetleyicinin HomeHTTP POST Index yöntem testleri aşağıdakileri doğrular:

  • ModelState.IsValid olduğundafalse, eylem yöntemi uygun verilerle 400 Hatalı İstekViewResult döndürür.
  • olduğunda ModelState.IsValidtrue:
    • Add Depodaki yöntemi çağrılır.
    • doğru RedirectToActionResult bağımsız değişkenlerle döndürülür.

Geçersiz bir model durumu, aşağıdaki ilk testte gösterildiği gibi kullanılarak AddModelError hata eklenerek test edilir:

[Fact]
public async Task IndexPost_ReturnsBadRequestResult_WhenModelStateIsInvalid()
{
    // Arrange
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.ListAsync())
        .ReturnsAsync(GetTestSessions());
    var controller = new HomeController(mockRepo.Object);
    controller.ModelState.AddModelError("SessionName", "Required");
    var newSession = new HomeController.NewSessionModel();

    // Act
    var result = await controller.Index(newSession);

    // Assert
    var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
    Assert.IsType<SerializableError>(badRequestResult.Value);
}

[Fact]
public async Task IndexPost_ReturnsARedirectAndAddsSession_WhenModelStateIsValid()
{
    // Arrange
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.AddAsync(It.IsAny<BrainstormSession>()))
        .Returns(Task.CompletedTask)
        .Verifiable();
    var controller = new HomeController(mockRepo.Object);
    var newSession = new HomeController.NewSessionModel()
    {
        SessionName = "Test Name"
    };

    // Act
    var result = await controller.Index(newSession);

    // Assert
    var redirectToActionResult = Assert.IsType<RedirectToActionResult>(result);
    Assert.Null(redirectToActionResult.ControllerName);
    Assert.Equal("Index", redirectToActionResult.ActionName);
    mockRepo.Verify();
}

ModelState geçerli olmadığında, get isteğiyle aynı ViewResult değer döndürülür. Test geçersiz bir model geçirmeyi denemez. Model bağlaması çalışmadığından (tümleştirme testi model bağlamayı kullansa da) geçersiz bir model geçirmek geçerli bir yaklaşım değildir. Bu durumda model bağlaması test edilmedi. Bu birim testleri yalnızca eylem yöntemindeki kodu test eder.

İkinci test, geçerli olduğunda ModelState bunu doğrular:

  • Yeni BrainstormSession bir eklenmiştir (depo aracılığıyla).
  • yöntemi beklenen özelliklere sahip bir RedirectToActionResult döndürür.

Çağrılmayan sahte çağrılar normalde yoksayılır, ancak Verifiable kurulum çağrısının sonunda çağrılması testte sahte doğrulamaya olanak tanır. Bu, beklenen yöntem çağrılmadıysa testi başarısız olan çağrısıyla mockRepo.Verifygerçekleştirilir.

Dekont

Bu örnekte kullanılan Moq kitaplığı, doğrulanabilir veya "katı" olan sahteleri doğrulanamayan sahtelerle ("gevşek" sahteler veya saplamalar olarak da adlandırılır) karıştırmayı mümkün kılar. Moq ile Sahte davranışı özelleştirme hakkında daha fazla bilgi edinin.

Örnek uygulamadaki SessionController , belirli bir beyin fırtınası oturumuyla ilgili bilgileri görüntüler. Denetleyici geçersiz id değerlerle ilgilenmek için mantık içerir (aşağıdaki örnekte bu senaryoları kapsayan iki return senaryo vardır). Son return deyim görünüme yeni StormSessionViewModel bir değer döndürür (Controllers/SessionController.cs):

public class SessionController : Controller
{
    private readonly IBrainstormSessionRepository _sessionRepository;

    public SessionController(IBrainstormSessionRepository sessionRepository)
    {
        _sessionRepository = sessionRepository;
    }

    public async Task<IActionResult> Index(int? id)
    {
        if (!id.HasValue)
        {
            return RedirectToAction(actionName: nameof(Index), 
                controllerName: "Home");
        }

        var session = await _sessionRepository.GetByIdAsync(id.Value);
        if (session == null)
        {
            return Content("Session not found.");
        }

        var viewModel = new StormSessionViewModel()
        {
            DateCreated = session.DateCreated,
            Name = session.Name,
            Id = session.Id
        };

        return View(viewModel);
    }
}

Birim testleri, Oturum denetleyicisi Index eylemindeki her return senaryo için bir test içerir:

[Fact]
public async Task IndexReturnsARedirectToIndexHomeWhenIdIsNull()
{
    // Arrange
    var controller = new SessionController(sessionRepository: null);

    // Act
    var result = await controller.Index(id: null);

    // Assert
    var redirectToActionResult = 
        Assert.IsType<RedirectToActionResult>(result);
    Assert.Equal("Home", redirectToActionResult.ControllerName);
    Assert.Equal("Index", redirectToActionResult.ActionName);
}

[Fact]
public async Task IndexReturnsContentWithSessionNotFoundWhenSessionNotFound()
{
    // Arrange
    int testSessionId = 1;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync((BrainstormSession)null);
    var controller = new SessionController(mockRepo.Object);

    // Act
    var result = await controller.Index(testSessionId);

    // Assert
    var contentResult = Assert.IsType<ContentResult>(result);
    Assert.Equal("Session not found.", contentResult.Content);
}

[Fact]
public async Task IndexReturnsViewResultWithStormSessionViewModel()
{
    // Arrange
    int testSessionId = 1;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(GetTestSessions().FirstOrDefault(
            s => s.Id == testSessionId));
    var controller = new SessionController(mockRepo.Object);

    // Act
    var result = await controller.Index(testSessionId);

    // Assert
    var viewResult = Assert.IsType<ViewResult>(result);
    var model = Assert.IsType<StormSessionViewModel>(
        viewResult.ViewData.Model);
    Assert.Equal("Test One", model.Name);
    Assert.Equal(2, model.DateCreated.Day);
    Assert.Equal(testSessionId, model.Id);
}

Fikirler denetleyicisine taşınan uygulama, yönlendirmede api/ideas web API'si olarak işlevselliği kullanıma sunar:

  • Bir beyin fırtınası oturumuyla ilişkili fikirlerin (IdeaDTO) listesi yöntemi tarafından ForSession döndürülür.
  • Create yöntemi bir oturuma yeni fikirler ekler.
[HttpGet("forsession/{sessionId}")]
public async Task<IActionResult> ForSession(int sessionId)
{
    var session = await _sessionRepository.GetByIdAsync(sessionId);
    if (session == null)
    {
        return NotFound(sessionId);
    }

    var result = session.Ideas.Select(idea => new IdeaDTO()
    {
        Id = idea.Id,
        Name = idea.Name,
        Description = idea.Description,
        DateCreated = idea.DateCreated
    }).ToList();

    return Ok(result);
}

[HttpPost("create")]
public async Task<IActionResult> Create([FromBody]NewIdeaModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var session = await _sessionRepository.GetByIdAsync(model.SessionId);
    if (session == null)
    {
        return NotFound(model.SessionId);
    }

    var idea = new Idea()
    {
        DateCreated = DateTimeOffset.Now,
        Description = model.Description,
        Name = model.Name
    };
    session.AddIdea(idea);

    await _sessionRepository.UpdateAsync(session);

    return Ok(session);
}

İş etki alanı varlıklarını doğrudan API çağrıları aracılığıyla döndürmekten kaçının. Etki alanı varlıkları:

  • Genellikle istemcinin gerektirdiğinden daha fazla veri ekleyin.
  • Uygulamanın iç etki alanı modelini gereksiz yere genel kullanıma sunulan API ile ilişkilendirin.

Etki alanı varlıkları ile istemciye döndürülen türler arasında eşleme gerçekleştirilebilir:

Ardından örnek uygulama, Ideas denetleyicisinin Create ve ForSession API yöntemleri için birim testlerini gösterir.

Örnek uygulama iki ForSession test içerir. İlk test, geçersiz bir NotFoundObjectResult oturum için bir (HTTP Bulunamadı) döndürip döndürmediğini ForSession belirler:

[Fact]
public async Task ForSession_ReturnsHttpNotFound_ForInvalidSession()
{
    // Arrange
    int testSessionId = 123;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync((BrainstormSession)null);
    var controller = new IdeasController(mockRepo.Object);

    // Act
    var result = await controller.ForSession(testSessionId);

    // Assert
    var notFoundObjectResult = Assert.IsType<NotFoundObjectResult>(result);
    Assert.Equal(testSessionId, notFoundObjectResult.Value);
}

İkinci ForSession test, geçerli bir oturum için oturum fikirlerinin () listesinin döndürülp<List<IdeaDTO>> döndürülmediğini ForSession belirler. Denetimler, özelliğinin doğru olduğunu onaylamak Name için ilk fikri de inceler:

[Fact]
public async Task ForSession_ReturnsIdeasForSession()
{
    // Arrange
    int testSessionId = 123;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(GetTestSession());
    var controller = new IdeasController(mockRepo.Object);

    // Act
    var result = await controller.ForSession(testSessionId);

    // Assert
    var okResult = Assert.IsType<OkObjectResult>(result);
    var returnValue = Assert.IsType<List<IdeaDTO>>(okResult.Value);
    var idea = returnValue.FirstOrDefault();
    Assert.Equal("One", idea.Name);
}

geçersiz olduğunda ModelState yönteminin Create davranışını test etmek için örnek uygulama, test kapsamında denetleyiciye bir model hatası ekler. Birim testlerinde model doğrulamayı veya model bağlamayı test etmeye çalışmayın; yalnızca geçersiz ModelStatebir ile karşılaştığınızda eylem yönteminin davranışını test edin:

[Fact]
public async Task Create_ReturnsBadRequest_GivenInvalidModel()
{
    // Arrange & Act
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    var controller = new IdeasController(mockRepo.Object);
    controller.ModelState.AddModelError("error", "some error");

    // Act
    var result = await controller.Create(model: null);

    // Assert
    Assert.IsType<BadRequestObjectResult>(result);
}

İkinci testi Create , döndüren nulldepoya bağlıdır, bu nedenle sahte depo döndürecek nullşekilde yapılandırılır. Bir test veritabanı (bellekte veya başka bir şekilde) oluşturmanıza ve bu sonucu döndüren bir sorgu oluşturmanıza gerek yoktur. Test, örnek kodda gösterildiği gibi tek bir deyimde gerçekleştirilebilir:

[Fact]
public async Task Create_ReturnsHttpNotFound_ForInvalidSession()
{
    // Arrange
    int testSessionId = 123;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync((BrainstormSession)null);
    var controller = new IdeasController(mockRepo.Object);

    // Act
    var result = await controller.Create(new NewIdeaModel());

    // Assert
    Assert.IsType<NotFoundObjectResult>(result);
}

Üçüncü Create test olan Create_ReturnsNewlyCreatedIdeaForSession, deponun UpdateAsync yönteminin çağrıldığını doğrular. Sahte ile çağrılır Verifiableve doğrulanabilir yöntemin yürütülür olduğunu onaylamak için sahte deponun Verify yöntemi çağrılır. Yöntemin verileri kaydettiğinden emin olmak UpdateAsync birim testinin sorumluluğu değildir. Bu işlem tümleştirme testiyle gerçekleştirilebilir.

[Fact]
public async Task Create_ReturnsNewlyCreatedIdeaForSession()
{
    // Arrange
    int testSessionId = 123;
    string testName = "test name";
    string testDescription = "test description";
    var testSession = GetTestSession();
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(testSession);
    var controller = new IdeasController(mockRepo.Object);

    var newIdea = new NewIdeaModel()
    {
        Description = testDescription,
        Name = testName,
        SessionId = testSessionId
    };
    mockRepo.Setup(repo => repo.UpdateAsync(testSession))
        .Returns(Task.CompletedTask)
        .Verifiable();

    // Act
    var result = await controller.Create(newIdea);

    // Assert
    var okResult = Assert.IsType<OkObjectResult>(result);
    var returnSession = Assert.IsType<BrainstormSession>(okResult.Value);
    mockRepo.Verify();
    Assert.Equal(2, returnSession.Ideas.Count());
    Assert.Equal(testName, returnSession.Ideas.LastOrDefault().Name);
    Assert.Equal(testDescription, returnSession.Ideas.LastOrDefault().Description);
}

Test ActionResult<T>

ActionResult<T> (ActionResult<TValue>), belirli bir türden türetilen ActionResult bir tür döndürebilir veya döndürebilir.

Örnek uygulama, belirli bir oturum idiçin bir List<IdeaDTO> döndüren bir yöntem içerir. Oturum id yoksa denetleyici döndürür NotFound:

[HttpGet("forsessionactionresult/{sessionId}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<ActionResult<List<IdeaDTO>>> ForSessionActionResult(int sessionId)
{
    var session = await _sessionRepository.GetByIdAsync(sessionId);

    if (session == null)
    {
        return NotFound(sessionId);
    }

    var result = session.Ideas.Select(idea => new IdeaDTO()
    {
        Id = idea.Id,
        Name = idea.Name,
        Description = idea.Description,
        DateCreated = idea.DateCreated
    }).ToList();

    return result;
}

denetleyicinin ForSessionActionResult iki testi içinde ApiIdeasControllerTestsyer alır.

İlk test, denetleyicinin var olmayan bir ActionResult oturum idiçin var olmayan bir fikir listesi döndürdüğünü onaylar:

[Fact]
public async Task ForSessionActionResult_ReturnsNotFoundObjectResultForNonexistentSession()
{
    // Arrange
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    var controller = new IdeasController(mockRepo.Object);
    var nonExistentSessionId = 999;

    // Act
    var result = await controller.ForSessionActionResult(nonExistentSessionId);

    // Assert
    var actionResult = Assert.IsType<ActionResult<List<IdeaDTO>>>(result);
    Assert.IsType<NotFoundObjectResult>(actionResult.Result);
}

Geçerli bir oturum idiçin, ikinci test yöntemin döndürdüğünü onaylar:

  • ActionResult Türü olan birList<IdeaDTO>.
  • ActionResult<T>. Değer bir List<IdeaDTO> türdür.
  • Listedeki ilk öğe, sahte oturumda depolanan fikirle eşleşen geçerli bir fikirdir (çağrılarak GetTestSessionelde edilir).
[Fact]
public async Task ForSessionActionResult_ReturnsIdeasForSession()
{
    // Arrange
    int testSessionId = 123;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(GetTestSession());
    var controller = new IdeasController(mockRepo.Object);

    // Act
    var result = await controller.ForSessionActionResult(testSessionId);

    // Assert
    var actionResult = Assert.IsType<ActionResult<List<IdeaDTO>>>(result);
    var returnValue = Assert.IsType<List<IdeaDTO>>(actionResult.Value);
    var idea = returnValue.FirstOrDefault();
    Assert.Equal("One", idea.Name);
}

Örnek uygulama ayrıca belirli bir oturum için yeni Idea bir oluşturma yöntemi de içerir. Denetleyici şunu döndürür:

[HttpPost("createactionresult")]
[ProducesResponseType(201)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
public async Task<ActionResult<BrainstormSession>> CreateActionResult([FromBody]NewIdeaModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var session = await _sessionRepository.GetByIdAsync(model.SessionId);

    if (session == null)
    {
        return NotFound(model.SessionId);
    }

    var idea = new Idea()
    {
        DateCreated = DateTimeOffset.Now,
        Description = model.Description,
        Name = model.Name
    };
    session.AddIdea(idea);

    await _sessionRepository.UpdateAsync(session);

    return CreatedAtAction(nameof(CreateActionResult), new { id = session.Id }, session);
}

üç testi CreateActionResult içinde ApiIdeasControllerTestsyer alır.

İlk metin, geçersiz bir model için döndürüldüğünü BadRequest onaylar.

[Fact]
public async Task CreateActionResult_ReturnsBadRequest_GivenInvalidModel()
{
    // Arrange & Act
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    var controller = new IdeasController(mockRepo.Object);
    controller.ModelState.AddModelError("error", "some error");

    // Act
    var result = await controller.CreateActionResult(model: null);

    // Assert
    var actionResult = Assert.IsType<ActionResult<BrainstormSession>>(result);
    Assert.IsType<BadRequestObjectResult>(actionResult.Result);
}

İkinci test, oturum yoksa döndürüldüğünü NotFound denetler.

[Fact]
public async Task CreateActionResult_ReturnsNotFoundObjectResultForNonexistentSession()
{
    // Arrange
    var nonExistentSessionId = 999;
    string testName = "test name";
    string testDescription = "test description";
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    var controller = new IdeasController(mockRepo.Object);

    var newIdea = new NewIdeaModel()
    {
        Description = testDescription,
        Name = testName,
        SessionId = nonExistentSessionId
    };

    // Act
    var result = await controller.CreateActionResult(newIdea);

    // Assert
    var actionResult = Assert.IsType<ActionResult<BrainstormSession>>(result);
    Assert.IsType<NotFoundObjectResult>(actionResult.Result);
}

Geçerli bir oturum idiçin son test şunları onaylar:

  • yöntemi türüne sahip bir ActionResultBrainstormSession döndürür.
  • ActionResult<T>. Sonuç bir CreatedAtActionResult'dir. CreatedAtActionResult, üst bilgi içeren 201 Created yanıtına Location benzer.
  • ActionResult<T>. Değer bir BrainstormSession türdür.
  • oturumunu UpdateAsync(testSession)güncelleştirmek için sahte çağrı çağrıldı. Yöntem Verifiable çağrısı onaylarda yürütülerek mockRepo.Verify() denetlenir.
  • Oturum için iki Idea nesne döndürülür.
  • Son öğe ( Idea sahte çağrı UpdateAsynctarafından öğesinin eklenmesi) testteki oturuma eklenen öğeyle eşleşir newIdea .
[Fact]
public async Task CreateActionResult_ReturnsNewlyCreatedIdeaForSession()
{
    // Arrange
    int testSessionId = 123;
    string testName = "test name";
    string testDescription = "test description";
    var testSession = GetTestSession();
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(testSession);
    var controller = new IdeasController(mockRepo.Object);

    var newIdea = new NewIdeaModel()
    {
        Description = testDescription,
        Name = testName,
        SessionId = testSessionId
    };
    mockRepo.Setup(repo => repo.UpdateAsync(testSession))
        .Returns(Task.CompletedTask)
        .Verifiable();

    // Act
    var result = await controller.CreateActionResult(newIdea);

    // Assert
    var actionResult = Assert.IsType<ActionResult<BrainstormSession>>(result);
    var createdAtActionResult = Assert.IsType<CreatedAtActionResult>(actionResult.Result);
    var returnValue = Assert.IsType<BrainstormSession>(createdAtActionResult.Value);
    mockRepo.Verify();
    Assert.Equal(2, returnValue.Ideas.Count());
    Assert.Equal(testName, returnValue.Ideas.LastOrDefault().Name);
    Assert.Equal(testDescription, returnValue.Ideas.LastOrDefault().Description);
}

Denetleyiciler herhangi bir ASP.NET Core MVC uygulamasında merkezi bir rol oynar. Bu nedenle, denetleyicilerin amaçlanan şekilde davrandığını bilmelisiniz. Otomatikleştirilmiş testler, uygulama bir üretim ortamına dağıtılmadan önce hataları algılayabilir.

Örnek kodu görüntüleme veya indirme (indirme)

Denetleyici mantığının birim testleri

Birim testleri , bir uygulamanın bir bölümünü altyapısından ve bağımlılıklarından yalıtılarak test etmeyi içerir. Birim testi denetleyicisi mantığı, bağımlılıklarının veya çerçevenin davranışını değil, yalnızca tek bir eylemin içeriğini test eder.

Denetleyicinin davranışına odaklanmak için denetleyici eylemlerinin birim testlerini ayarlayın. Denetleyici birim testi filtreler, yönlendirme ve model bağlama gibi senaryoları önler. Bir isteğe toplu olarak yanıt veren bileşenler arasındaki etkileşimleri kapsayan testler tümleştirme testleri tarafından işlenir. Tümleştirme testleri hakkında daha fazla bilgi için bkz . ASP.NET Core'da tümleştirme testleri.

Özel filtreler ve yollar yazıyorsanız, birim testi bunları belirli bir denetleyici eylemindeki testlerin parçası olarak değil yalıtımlı olarak test edin.

Denetleyici birim testlerini göstermek için örnek uygulamada aşağıdaki denetleyiciyi gözden geçirin. Denetleyici Home , beyin fırtınası oturumlarının listesini görüntüler ve POST isteğiyle yeni beyin fırtınası oturumları oluşturulmasına olanak tanır:

public class HomeController : Controller
{
    private readonly IBrainstormSessionRepository _sessionRepository;

    public HomeController(IBrainstormSessionRepository sessionRepository)
    {
        _sessionRepository = sessionRepository;
    }

    public async Task<IActionResult> Index()
    {
        var sessionList = await _sessionRepository.ListAsync();

        var model = sessionList.Select(session => new StormSessionViewModel()
        {
            Id = session.Id,
            DateCreated = session.DateCreated,
            Name = session.Name,
            IdeaCount = session.Ideas.Count
        });

        return View(model);
    }

    public class NewSessionModel
    {
        [Required]
        public string SessionName { get; set; }
    }

    [HttpPost]
    public async Task<IActionResult> Index(NewSessionModel model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        else
        {
            await _sessionRepository.AddAsync(new BrainstormSession()
            {
                DateCreated = DateTimeOffset.Now,
                Name = model.SessionName
            });
        }

        return RedirectToAction(actionName: nameof(Index));
    }
}

Önceki denetleyici:

  • Açık Bağımlılıklar İlkesi'ni izler.
  • Bağımlılık eklemenin (DI) bir örneğini sağlamasını IBrainstormSessionRepositorybekler.
  • Moq gibi bir sahte IBrainstormSessionRepository nesne çerçevesi kullanılarak sahte bir hizmetle test edilebilir. Sahte nesne, test için kullanılan önceden belirlenmiş bir özellik ve yöntem davranışları kümesine sahip, oluşturulmuş bir nesnedir. Daha fazla bilgi için bkz . Tümleştirme testlerine giriş.

Yöntemin HTTP GET Index döngü veya dallanma yoktur ve yalnızca bir yöntemi çağırır. Bu eylem için birim testi:

  • IBrainstormSessionRepository yöntemini kullanarak hizmetle dalga geçerGetTestSessions. GetTestSessions tarihler ve oturum adları içeren iki sahte beyin fırtınası oturumu oluşturur.
  • yöntemini yürütür Index .
  • yöntemi tarafından döndürülen sonuç üzerinde onaylar yapar:
[Fact]
public async Task Index_ReturnsAViewResult_WithAListOfBrainstormSessions()
{
    // Arrange
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.ListAsync())
        .ReturnsAsync(GetTestSessions());
    var controller = new HomeController(mockRepo.Object);

    // Act
    var result = await controller.Index();

    // Assert
    var viewResult = Assert.IsType<ViewResult>(result);
    var model = Assert.IsAssignableFrom<IEnumerable<StormSessionViewModel>>(
        viewResult.ViewData.Model);
    Assert.Equal(2, model.Count());
}
private List<BrainstormSession> GetTestSessions()
{
    var sessions = new List<BrainstormSession>();
    sessions.Add(new BrainstormSession()
    {
        DateCreated = new DateTime(2016, 7, 2),
        Id = 1,
        Name = "Test One"
    });
    sessions.Add(new BrainstormSession()
    {
        DateCreated = new DateTime(2016, 7, 1),
        Id = 2,
        Name = "Test Two"
    });
    return sessions;
}

Denetleyicinin HomeHTTP POST Index yöntem testleri aşağıdakileri doğrular:

  • ModelState.IsValid olduğundafalse, eylem yöntemi uygun verilerle 400 Hatalı İstekViewResult döndürür.
  • olduğunda ModelState.IsValidtrue:
    • Add Depodaki yöntemi çağrılır.
    • doğru RedirectToActionResult bağımsız değişkenlerle döndürülür.

Geçersiz bir model durumu, aşağıdaki ilk testte gösterildiği gibi kullanılarak AddModelError hata eklenerek test edilir:

[Fact]
public async Task IndexPost_ReturnsBadRequestResult_WhenModelStateIsInvalid()
{
    // Arrange
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.ListAsync())
        .ReturnsAsync(GetTestSessions());
    var controller = new HomeController(mockRepo.Object);
    controller.ModelState.AddModelError("SessionName", "Required");
    var newSession = new HomeController.NewSessionModel();

    // Act
    var result = await controller.Index(newSession);

    // Assert
    var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
    Assert.IsType<SerializableError>(badRequestResult.Value);
}

[Fact]
public async Task IndexPost_ReturnsARedirectAndAddsSession_WhenModelStateIsValid()
{
    // Arrange
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.AddAsync(It.IsAny<BrainstormSession>()))
        .Returns(Task.CompletedTask)
        .Verifiable();
    var controller = new HomeController(mockRepo.Object);
    var newSession = new HomeController.NewSessionModel()
    {
        SessionName = "Test Name"
    };

    // Act
    var result = await controller.Index(newSession);

    // Assert
    var redirectToActionResult = Assert.IsType<RedirectToActionResult>(result);
    Assert.Null(redirectToActionResult.ControllerName);
    Assert.Equal("Index", redirectToActionResult.ActionName);
    mockRepo.Verify();
}

ModelState geçerli olmadığında, get isteğiyle aynı ViewResult değer döndürülür. Test geçersiz bir model geçirmeyi denemez. Model bağlaması çalışmadığından (tümleştirme testi model bağlamayı kullansa da) geçersiz bir model geçirmek geçerli bir yaklaşım değildir. Bu durumda model bağlaması test edilmedi. Bu birim testleri yalnızca eylem yöntemindeki kodu test eder.

İkinci test, geçerli olduğunda ModelState bunu doğrular:

  • Yeni BrainstormSession bir eklenmiştir (depo aracılığıyla).
  • yöntemi beklenen özelliklere sahip bir RedirectToActionResult döndürür.

Çağrılmayan sahte çağrılar normalde yoksayılır, ancak Verifiable kurulum çağrısının sonunda çağrılması testte sahte doğrulamaya olanak tanır. Bu, beklenen yöntem çağrılmadıysa testi başarısız olan çağrısıyla mockRepo.Verifygerçekleştirilir.

Dekont

Bu örnekte kullanılan Moq kitaplığı, doğrulanabilir veya "katı" olan sahteleri doğrulanamayan sahtelerle ("gevşek" sahteler veya saplamalar olarak da adlandırılır) karıştırmayı mümkün kılar. Moq ile Sahte davranışı özelleştirme hakkında daha fazla bilgi edinin.

Örnek uygulamadaki SessionController , belirli bir beyin fırtınası oturumuyla ilgili bilgileri görüntüler. Denetleyici geçersiz id değerlerle ilgilenmek için mantık içerir (aşağıdaki örnekte bu senaryoları kapsayan iki return senaryo vardır). Son return deyim görünüme yeni StormSessionViewModel bir değer döndürür (Controllers/SessionController.cs):

public class SessionController : Controller
{
    private readonly IBrainstormSessionRepository _sessionRepository;

    public SessionController(IBrainstormSessionRepository sessionRepository)
    {
        _sessionRepository = sessionRepository;
    }

    public async Task<IActionResult> Index(int? id)
    {
        if (!id.HasValue)
        {
            return RedirectToAction(actionName: nameof(Index), 
                controllerName: "Home");
        }

        var session = await _sessionRepository.GetByIdAsync(id.Value);
        if (session == null)
        {
            return Content("Session not found.");
        }

        var viewModel = new StormSessionViewModel()
        {
            DateCreated = session.DateCreated,
            Name = session.Name,
            Id = session.Id
        };

        return View(viewModel);
    }
}

Birim testleri, Oturum denetleyicisi Index eylemindeki her return senaryo için bir test içerir:

[Fact]
public async Task IndexReturnsARedirectToIndexHomeWhenIdIsNull()
{
    // Arrange
    var controller = new SessionController(sessionRepository: null);

    // Act
    var result = await controller.Index(id: null);

    // Assert
    var redirectToActionResult = 
        Assert.IsType<RedirectToActionResult>(result);
    Assert.Equal("Home", redirectToActionResult.ControllerName);
    Assert.Equal("Index", redirectToActionResult.ActionName);
}

[Fact]
public async Task IndexReturnsContentWithSessionNotFoundWhenSessionNotFound()
{
    // Arrange
    int testSessionId = 1;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync((BrainstormSession)null);
    var controller = new SessionController(mockRepo.Object);

    // Act
    var result = await controller.Index(testSessionId);

    // Assert
    var contentResult = Assert.IsType<ContentResult>(result);
    Assert.Equal("Session not found.", contentResult.Content);
}

[Fact]
public async Task IndexReturnsViewResultWithStormSessionViewModel()
{
    // Arrange
    int testSessionId = 1;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(GetTestSessions().FirstOrDefault(
            s => s.Id == testSessionId));
    var controller = new SessionController(mockRepo.Object);

    // Act
    var result = await controller.Index(testSessionId);

    // Assert
    var viewResult = Assert.IsType<ViewResult>(result);
    var model = Assert.IsType<StormSessionViewModel>(
        viewResult.ViewData.Model);
    Assert.Equal("Test One", model.Name);
    Assert.Equal(2, model.DateCreated.Day);
    Assert.Equal(testSessionId, model.Id);
}

Fikirler denetleyicisine taşınan uygulama, yönlendirmede api/ideas web API'si olarak işlevselliği kullanıma sunar:

  • Bir beyin fırtınası oturumuyla ilişkili fikirlerin (IdeaDTO) listesi yöntemi tarafından ForSession döndürülür.
  • Create yöntemi bir oturuma yeni fikirler ekler.
[HttpGet("forsession/{sessionId}")]
public async Task<IActionResult> ForSession(int sessionId)
{
    var session = await _sessionRepository.GetByIdAsync(sessionId);
    if (session == null)
    {
        return NotFound(sessionId);
    }

    var result = session.Ideas.Select(idea => new IdeaDTO()
    {
        Id = idea.Id,
        Name = idea.Name,
        Description = idea.Description,
        DateCreated = idea.DateCreated
    }).ToList();

    return Ok(result);
}

[HttpPost("create")]
public async Task<IActionResult> Create([FromBody]NewIdeaModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var session = await _sessionRepository.GetByIdAsync(model.SessionId);
    if (session == null)
    {
        return NotFound(model.SessionId);
    }

    var idea = new Idea()
    {
        DateCreated = DateTimeOffset.Now,
        Description = model.Description,
        Name = model.Name
    };
    session.AddIdea(idea);

    await _sessionRepository.UpdateAsync(session);

    return Ok(session);
}

İş etki alanı varlıklarını doğrudan API çağrıları aracılığıyla döndürmekten kaçının. Etki alanı varlıkları:

  • Genellikle istemcinin gerektirdiğinden daha fazla veri ekleyin.
  • Uygulamanın iç etki alanı modelini gereksiz yere genel kullanıma sunulan API ile ilişkilendirin.

Etki alanı varlıkları ile istemciye döndürülen türler arasında eşleme gerçekleştirilebilir:

Ardından örnek uygulama, Ideas denetleyicisinin Create ve ForSession API yöntemleri için birim testlerini gösterir.

Örnek uygulama iki ForSession test içerir. İlk test, geçersiz bir NotFoundObjectResult oturum için bir (HTTP Bulunamadı) döndürip döndürmediğini ForSession belirler:

[Fact]
public async Task ForSession_ReturnsHttpNotFound_ForInvalidSession()
{
    // Arrange
    int testSessionId = 123;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync((BrainstormSession)null);
    var controller = new IdeasController(mockRepo.Object);

    // Act
    var result = await controller.ForSession(testSessionId);

    // Assert
    var notFoundObjectResult = Assert.IsType<NotFoundObjectResult>(result);
    Assert.Equal(testSessionId, notFoundObjectResult.Value);
}

İkinci ForSession test, geçerli bir oturum için oturum fikirlerinin () listesinin döndürülp<List<IdeaDTO>> döndürülmediğini ForSession belirler. Denetimler, özelliğinin doğru olduğunu onaylamak Name için ilk fikri de inceler:

[Fact]
public async Task ForSession_ReturnsIdeasForSession()
{
    // Arrange
    int testSessionId = 123;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(GetTestSession());
    var controller = new IdeasController(mockRepo.Object);

    // Act
    var result = await controller.ForSession(testSessionId);

    // Assert
    var okResult = Assert.IsType<OkObjectResult>(result);
    var returnValue = Assert.IsType<List<IdeaDTO>>(okResult.Value);
    var idea = returnValue.FirstOrDefault();
    Assert.Equal("One", idea.Name);
}

geçersiz olduğunda ModelState yönteminin Create davranışını test etmek için örnek uygulama, test kapsamında denetleyiciye bir model hatası ekler. Birim testlerinde model doğrulamayı veya model bağlamayı test etmeye çalışmayın; yalnızca geçersiz ModelStatebir ile karşılaştığınızda eylem yönteminin davranışını test edin:

[Fact]
public async Task Create_ReturnsBadRequest_GivenInvalidModel()
{
    // Arrange & Act
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    var controller = new IdeasController(mockRepo.Object);
    controller.ModelState.AddModelError("error", "some error");

    // Act
    var result = await controller.Create(model: null);

    // Assert
    Assert.IsType<BadRequestObjectResult>(result);
}

İkinci testi Create , döndüren nulldepoya bağlıdır, bu nedenle sahte depo döndürecek nullşekilde yapılandırılır. Bir test veritabanı (bellekte veya başka bir şekilde) oluşturmanıza ve bu sonucu döndüren bir sorgu oluşturmanıza gerek yoktur. Test, örnek kodda gösterildiği gibi tek bir deyimde gerçekleştirilebilir:

[Fact]
public async Task Create_ReturnsHttpNotFound_ForInvalidSession()
{
    // Arrange
    int testSessionId = 123;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync((BrainstormSession)null);
    var controller = new IdeasController(mockRepo.Object);

    // Act
    var result = await controller.Create(new NewIdeaModel());

    // Assert
    Assert.IsType<NotFoundObjectResult>(result);
}

Üçüncü Create test olan Create_ReturnsNewlyCreatedIdeaForSession, deponun UpdateAsync yönteminin çağrıldığını doğrular. Sahte ile çağrılır Verifiableve doğrulanabilir yöntemin yürütülür olduğunu onaylamak için sahte deponun Verify yöntemi çağrılır. Yöntemin verileri kaydettiğinden emin olmak UpdateAsync birim testinin sorumluluğu değildir. Bu işlem tümleştirme testiyle gerçekleştirilebilir.

[Fact]
public async Task Create_ReturnsNewlyCreatedIdeaForSession()
{
    // Arrange
    int testSessionId = 123;
    string testName = "test name";
    string testDescription = "test description";
    var testSession = GetTestSession();
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(testSession);
    var controller = new IdeasController(mockRepo.Object);

    var newIdea = new NewIdeaModel()
    {
        Description = testDescription,
        Name = testName,
        SessionId = testSessionId
    };
    mockRepo.Setup(repo => repo.UpdateAsync(testSession))
        .Returns(Task.CompletedTask)
        .Verifiable();

    // Act
    var result = await controller.Create(newIdea);

    // Assert
    var okResult = Assert.IsType<OkObjectResult>(result);
    var returnSession = Assert.IsType<BrainstormSession>(okResult.Value);
    mockRepo.Verify();
    Assert.Equal(2, returnSession.Ideas.Count());
    Assert.Equal(testName, returnSession.Ideas.LastOrDefault().Name);
    Assert.Equal(testDescription, returnSession.Ideas.LastOrDefault().Description);
}

Test ActionResult<T>

ASP.NET Core 2.1 veya sonraki sürümlerinde ActionResult <T> (ActionResult<TValue>), belirli bir türden ActionResult türetilen bir tür döndürmenizi veya döndürmenizi sağlar.

Örnek uygulama, belirli bir oturum idiçin bir List<IdeaDTO> döndüren bir yöntem içerir. Oturum id yoksa denetleyici döndürür NotFound:

[HttpGet("forsessionactionresult/{sessionId}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<ActionResult<List<IdeaDTO>>> ForSessionActionResult(int sessionId)
{
    var session = await _sessionRepository.GetByIdAsync(sessionId);

    if (session == null)
    {
        return NotFound(sessionId);
    }

    var result = session.Ideas.Select(idea => new IdeaDTO()
    {
        Id = idea.Id,
        Name = idea.Name,
        Description = idea.Description,
        DateCreated = idea.DateCreated
    }).ToList();

    return result;
}

denetleyicinin ForSessionActionResult iki testi içinde ApiIdeasControllerTestsyer alır.

İlk test, denetleyicinin var olmayan bir ActionResult oturum idiçin var olmayan bir fikir listesi döndürdüğünü onaylar:

[Fact]
public async Task ForSessionActionResult_ReturnsNotFoundObjectResultForNonexistentSession()
{
    // Arrange
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    var controller = new IdeasController(mockRepo.Object);
    var nonExistentSessionId = 999;

    // Act
    var result = await controller.ForSessionActionResult(nonExistentSessionId);

    // Assert
    var actionResult = Assert.IsType<ActionResult<List<IdeaDTO>>>(result);
    Assert.IsType<NotFoundObjectResult>(actionResult.Result);
}

Geçerli bir oturum idiçin, ikinci test yöntemin döndürdüğünü onaylar:

  • ActionResult Türü olan birList<IdeaDTO>.
  • ActionResult<T>. Değer bir List<IdeaDTO> türdür.
  • Listedeki ilk öğe, sahte oturumda depolanan fikirle eşleşen geçerli bir fikirdir (çağrılarak GetTestSessionelde edilir).
[Fact]
public async Task ForSessionActionResult_ReturnsIdeasForSession()
{
    // Arrange
    int testSessionId = 123;
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(GetTestSession());
    var controller = new IdeasController(mockRepo.Object);

    // Act
    var result = await controller.ForSessionActionResult(testSessionId);

    // Assert
    var actionResult = Assert.IsType<ActionResult<List<IdeaDTO>>>(result);
    var returnValue = Assert.IsType<List<IdeaDTO>>(actionResult.Value);
    var idea = returnValue.FirstOrDefault();
    Assert.Equal("One", idea.Name);
}

Örnek uygulama ayrıca belirli bir oturum için yeni Idea bir oluşturma yöntemi de içerir. Denetleyici şunu döndürür:

[HttpPost("createactionresult")]
[ProducesResponseType(201)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
public async Task<ActionResult<BrainstormSession>> CreateActionResult([FromBody]NewIdeaModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var session = await _sessionRepository.GetByIdAsync(model.SessionId);

    if (session == null)
    {
        return NotFound(model.SessionId);
    }

    var idea = new Idea()
    {
        DateCreated = DateTimeOffset.Now,
        Description = model.Description,
        Name = model.Name
    };
    session.AddIdea(idea);

    await _sessionRepository.UpdateAsync(session);

    return CreatedAtAction(nameof(CreateActionResult), new { id = session.Id }, session);
}

üç testi CreateActionResult içinde ApiIdeasControllerTestsyer alır.

İlk metin, geçersiz bir model için döndürüldüğünü BadRequest onaylar.

[Fact]
public async Task CreateActionResult_ReturnsBadRequest_GivenInvalidModel()
{
    // Arrange & Act
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    var controller = new IdeasController(mockRepo.Object);
    controller.ModelState.AddModelError("error", "some error");

    // Act
    var result = await controller.CreateActionResult(model: null);

    // Assert
    var actionResult = Assert.IsType<ActionResult<BrainstormSession>>(result);
    Assert.IsType<BadRequestObjectResult>(actionResult.Result);
}

İkinci test, oturum yoksa döndürüldüğünü NotFound denetler.

[Fact]
public async Task CreateActionResult_ReturnsNotFoundObjectResultForNonexistentSession()
{
    // Arrange
    var nonExistentSessionId = 999;
    string testName = "test name";
    string testDescription = "test description";
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    var controller = new IdeasController(mockRepo.Object);

    var newIdea = new NewIdeaModel()
    {
        Description = testDescription,
        Name = testName,
        SessionId = nonExistentSessionId
    };

    // Act
    var result = await controller.CreateActionResult(newIdea);

    // Assert
    var actionResult = Assert.IsType<ActionResult<BrainstormSession>>(result);
    Assert.IsType<NotFoundObjectResult>(actionResult.Result);
}

Geçerli bir oturum idiçin son test şunları onaylar:

  • yöntemi türüne sahip bir ActionResultBrainstormSession döndürür.
  • ActionResult<T>. Sonuç bir CreatedAtActionResult'dir. CreatedAtActionResult, üst bilgi içeren 201 Created yanıtına Location benzer.
  • ActionResult<T>. Değer bir BrainstormSession türdür.
  • oturumunu UpdateAsync(testSession)güncelleştirmek için sahte çağrı çağrıldı. Yöntem Verifiable çağrısı onaylarda yürütülerek mockRepo.Verify() denetlenir.
  • Oturum için iki Idea nesne döndürülür.
  • Son öğe ( Idea sahte çağrı UpdateAsynctarafından öğesinin eklenmesi) testteki oturuma eklenen öğeyle eşleşir newIdea .
[Fact]
public async Task CreateActionResult_ReturnsNewlyCreatedIdeaForSession()
{
    // Arrange
    int testSessionId = 123;
    string testName = "test name";
    string testDescription = "test description";
    var testSession = GetTestSession();
    var mockRepo = new Mock<IBrainstormSessionRepository>();
    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))
        .ReturnsAsync(testSession);
    var controller = new IdeasController(mockRepo.Object);

    var newIdea = new NewIdeaModel()
    {
        Description = testDescription,
        Name = testName,
        SessionId = testSessionId
    };
    mockRepo.Setup(repo => repo.UpdateAsync(testSession))
        .Returns(Task.CompletedTask)
        .Verifiable();

    // Act
    var result = await controller.CreateActionResult(newIdea);

    // Assert
    var actionResult = Assert.IsType<ActionResult<BrainstormSession>>(result);
    var createdAtActionResult = Assert.IsType<CreatedAtActionResult>(actionResult.Result);
    var returnValue = Assert.IsType<BrainstormSession>(createdAtActionResult.Value);
    mockRepo.Verify();
    Assert.Equal(2, returnValue.Ideas.Count());
    Assert.Equal(testName, returnValue.Ideas.LastOrDefault().Name);
    Assert.Equal(testDescription, returnValue.Ideas.LastOrDefault().Description);
}

Ek kaynaklar