2017-04-21 4 views
1

FrameworksUnit Test Änderungen speichern Fehler

.NETCoreApp 1.1 
EF Core 1.1.1 
Xunit 2.2.0 
Moq 4.7.8 

Controller-POST-Methode
_yourRepository im Controller Konstruktor injiziert wird und ist vom Typ IYourRepository

[HttpPost(Name = "CreateMethod")] 
public async Task<IActionResult> CreateMethod([FromBody] ObjectForCreationDto objectDto) 
{ 
    if (objectDto== null) 
    { 
     return BadRequest(); 
    } 

    if (!ModelState.IsValid) 
    { 
     return BadRequest(); 
    } 

    await _yourRespository.CreateObject(objectDto); 

    if (!await _yourRespository.Save()) 
    { 
     throw new Exception("Creating this object failed on save."); 
    }    

    return Ok(); 
} 

Unit Test, dass schlägt fehl

[Fact] 
public async Task CreateObject_WhenGoodDtoReceived_SuccessStatusReturned() 
{ 
    // Arrange 
    var mockRepo = new Mock<IYourRepository>(); 
    var controller = new YourController(mockRepo.Object); 
    var objectForCreationDto = new ObjectForCreationDto { Code = "0001", Name = "Object One" }; 

    // Act 
    var result = await controller.CreateObject(objectForCreationDto); 

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

Der Test schlägt fehl, weil die Leitung

if (!await _yourRespository.Save()) 

immer true ergibt. Wenn es um true können Sie sehen, dass der Code einen Fehler wirft (die von Middleware behandelt wird)

_yourRepository.Save() -Methode

public async Task<bool> Save() 
{ 
    return (await _yourContext.SaveChangesAsync() >= 0); 
} 

Ich bin nicht sicher, wie das Problem zu lösen und ich bin mir nicht 100% sicher, warum es scheitert.

Liegt es daran, dass die gespottete IYourRepository Schnittstelle keine Implementierung der Save Methode enthält?

Wenn ja, bedeutet das, die Post Methode zu testen, würde ich meinen DbContext spotten und mein YourRepository Objekt damit erstellen?

Jede Erklärung, warum dies versagt und wie es zu beheben viel

+0

statt 'erwarten _yourRespository.Save()' 'versuchen _yourRespository.Save(). Warten Sie()' –

+0

Er ist ein Mock verwenden, _yourRepository hat ** keine Funktionalität **. Das ist der springende Punkt eines Spottes, nicht eine konkrete Implementierung zu haben, sondern "gefälschte" Ergebnisse zu haben, die Sie wollen, dass es zurückkommt. – Tseng

Antwort

2

Sie müssen den Repo-Setup eine richtige Aufgabe von der Asynchron-Methode zurückzukehren. Moq ermöglicht dies mit ReturnsAsync

[Fact] 
public async Task CreateObject_WhenGoodDtoReceived_SuccessStatusReturned() 
{ 
    // Arrange 
    var mockRepo = new Mock<IYourRepository>(); 
    mockRepo.Setup(_ => _.Save()).ReturnsAsync(true);//<-- ADD THIS 
    var controller = new YourController(mockRepo.Object); 
    var objectForCreationDto = new ObjectForCreationDto { Code = "0001", Name = "Object One" }; 

    // Act 
    var result = await controller.CreateObject(objectForCreationDto); 

    // Assert 
    Assert.IsType<OkObjectResult>(result); 
} 
+0

Danke für die schnellen Antworten alle. Ich versuche immer noch, meinen Kopf dazu zu bringen. Wenn ich die Post-Methode so teste, bedeutet das nicht, dass ich nicht wirklich überprüfe, ob es funktioniert? Ich könnte alles reinlassen (vorausgesetzt, es ist ein korrektes Dto) und der Test wird bestehen ?? Oder testet das Save-Verhalten etwas, das für einen Integrationstest gespeichert werden soll (kein Wortspiel!)? – GreenyMcDuff

+0

Dies ist nur ein bestimmtes Szenario, das die CreateMethod-Methode des Controllers testet.Wir verspotten die Abhängigkeiten, um die zu testende Methode isoliert auszuüben. – Nkosi

+1

@GreenyMcDuff: Sie testen Ihre Controller-Aktion, nicht das Repository. Deshalb verspotten Sie das Repository, um den gewünschten Wert zurückzugeben. Wenn Sie beispielsweise sehen möchten, dass Action OkObjectResult zurückgibt, werden Sie "Save()" vortäuschen, um "True" zurückzugeben. Wenn Sie testen wollen, ob es eine Exception auslöst, maskieren Sie 'Save()', um 'false' zurückzugeben, um einen db-Fehler zu simulieren, ohne jemals den DB/DbContext selbst zu verwenden. Das ist der springende Punkt bei Mocks und ** Unit ** -Test (Unit Test bedeutet: Unit (Methode, Klasse, Property) testen ohne externe Abhängigkeiten zu verwenden – Tseng

1

ersetzen new Mock<IYourRepository>(); mit new Mock<IYourRepository>(MockBehavior.Strict); geschätzt würde - jetzt wird es Ausnahmen auslösen, wenn eine Methode ohne Setup genannt wird.

Offensichtlich sollten Sie etwas (wie Rückgabewerte) nicht überprüfen (bestätigen) Sie nicht bestimmt.

0

Mock Save Die Methode gibt standardmäßig false zurück. Sie müssen explizit Setup true als Rückgabewert:

mockRepo.Setup(x => x.Save()).Returns(Task<bool>.FromResult(true));