2017-11-21 1 views
1

Ich versuche, ein Datenrepository für meine Workorders im Unit-Test zu testen.Mongodb C# Komponententest: Objektreferenz nicht auf eine Objektinstanz festgelegt

Das Repository verwendet eine DatabaseContext-Instanz, die auf die mongodb-Datenbank zugreift und die IMongoCollection für die Arbeitsaufträge freigibt, wie Sie unten sehen können.

Ich benutze Moq, um Mocks sowohl der IMongoCollection und DatabaseContext zu machen. In der Moq-Einstellung für den DatabaseContext wähle ich, um die IMongoCollection zurückzugeben, wenn die exposed Workorder-Eigenschaft aufgerufen wird. Und wiederum die gespottete IMongoCollection gibt eine DeleteResult.Acknowledged (1) Aufgabe zurück, wenn DeleteOneAsync aufgerufen wird.

Auf diese Weise hoffte ich auf einige Komponententests, ohne dass die Datenbank ausgeführt werden musste, aber ich steckte mit einem Fehler fest und sagte mir "System.NullReferenceException : Object reference not set to an instance of an object." Objekt zurückgegeben DeleteResult.

Es scheint, wie mein Ergebnis nicht richtig erstellt wird, unter meinem Code.

Der Fehler selbst aufgetreten ist, wenn die Tests laufen

Test Name: MESAPITests.RepositoryTests.WorkorderRepositoryTests.DeleteWorkorderById_ReturnsBooleanTrue 
Test FullName: MESAPITests.RepositoryTests.WorkorderRepositoryTests.DeleteWorkorderById_ReturnsBooleanTrue 
Test Source: C:\Users\Zacke\Documents\Repositories\MES-API\MES-API Tests\RepositoryTests\WorkorderRepositoryTests.cs : line 22 
Test Outcome: Failed 
Test Duration: 0:00:00.354 

Result StackTrace: 
at MESAPI.Repositories.WorkorderRepository.<DeleteWorkorderById>d__2.MoveNext() in C:\Users\Zacke\Documents\Repositories\MES-API\MES-API\Repositories\WorkRepositories\WorkorderRepository.cs:line 28 
--- End of stack trace from previous location where exception was thrown ---  
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 
    at MESAPITests.RepositoryTests.WorkorderRepositoryTests.<DeleteWorkorderById_ReturnsBooleanTrue>d__1.MoveNext() in C:\Users\Zacke\Documents\Repositories\MES-API\MES-API Tests\RepositoryTests\WorkorderRepositoryTests.cs:line 34 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
Result Message: System.NullReferenceException : Object reference not set to an instance of an object. 

DataRepositoryTests

public class WorkorderRepositoryTests 
{ 
    private WorkorderRepository _repo; 

    [Fact] 
    public async void DeleteWorkorderById_ReturnsBooleanTrue() 
    { 
     var mockCollection = new Mock<IMongoCollection<Workorder>>(); 
     mockCollection 
      .Setup(_ => _.DeleteOneAsync(It.IsAny<Expression<Func<Workorder, bool>>>(), 
       default(CancellationToken))) 
      .ReturnsAsync(await Task.Run<DeleteResult>(() => new DeleteResult.Acknowledged(1))); 

     var mockContext = new Mock<IDatabaseContext>(); 
     mockContext.Setup(_ => _.Workorders).Returns(mockCollection.Object); 

     _repo = new WorkorderRepository(mockContext.Object); 
     var id = ObjectId.GenerateNewId().ToString(); 
     var result = await _repo.DeleteWorkorderById(id); 
     Assert.True(result); 
    } 
} 

WorkorderRepository Fehler auf der zweiten Linie in DeleteWorkorderById aufgetreten

public class WorkorderRepository : IWorkorderRepository 
{ 
    private readonly IMongoCollection<Workorder> _workorders; 

    public WorkorderRepository(IDatabaseContext context) 
    { 
     _workorders = context.Workorders; 
    } 

    public async Task<bool> DeleteWorkorderById(string id) 
    { 
     var result = await _workorders.DeleteOneAsync(w => w.Id == id); 
     return result.DeletedCount == 1; 
    } 

    public async Task<List<Workorder>> GetAllWorkordersAsList() 
    { 
     return await _workorders.FindAsync(new BsonDocument()).Result.ToListAsync(); 
    } 

    public async Task<Workorder> GetWorkorderById(string id) 
    { 
     return await _workorders.FindAsync(w => w.Id == id).Result.FirstOrDefaultAsync(); 
    } 

    public async Task<Workorder> PostNewWorkroder(WorkorderPost workorderPost) 
    { 
     var newWorkorder = new Workorder(workorderPost); 
     await _workorders.InsertOneAsync(newWorkorder); 
     return await _workorders.FindAsync(w => w.Id == newWorkorder.Id).Result.FirstOrDefaultAsync(); 
    } 

    public async Task<bool> UpdateWorkorder(Workorder workorder) 
    { 
     var result = await _workorders.ReplaceOneAsync(w => w.Id == workorder.Id, workorder); 
     return result.MatchedCount != 0; 
    } 
} 

IDatabaseRepository

public interface IDatabaseContext 
{ 
    /// <summary> 
    /// Mongo database context. 
    /// </summary> 
    IMongoDatabase Database { get; set; } 

    /// <summary> 
    /// BomFamily database context. 
    /// </summary> 
    IMongoCollection<BomFamily> BomFamilies { get; set; } 

    /// <summary> 
    /// BomGroup database context. 
    /// </summary> 
    IMongoCollection<BomGroup> BomGroups { get; set; } 

    /// <summary> 
    /// BomItem database context. 
    /// </summary> 
    IMongoCollection<BomItem> BomItems { get; set; } 

    /// <summary> 
    /// Event database context. 
    /// </summary> 
    IMongoCollection<Event> Events { get; set; } 

    /// <summary> 
    /// EventAttribute database context. 
    /// </summary> 
    IMongoCollection<EventAttribute> EventAttributes { get; set; } 

    /// <summary> 
    /// EventType database context. 
    /// </summary> 
    IMongoCollection<EventType> EventTypes { get; set; } 

    /// <summary> 
    /// Job database context. 
    /// </summary> 
    IMongoCollection<Job> Jobs { get; set; } 

    /// <summary> 
    /// Product database context. 
    /// </summary> 
    IMongoCollection<Product> Products { get; set; } 

    /// <summary> 
    /// QualityEvent database context. 
    /// </summary> 
    IMongoCollection<QualityEvent> QualityEvents { get; set; } 

    /// <summary> 
    /// QualityTest database context. 
    /// </summary> 
    IMongoCollection<QualityTest> QualityTests { get; set; } 

    /// <summary> 
    /// QualityVariable database context. 
    /// </summary> 
    IMongoCollection<QualityVariable> QualityVariables { get; set; } 

    /// <summary> 
    /// Status database context. 
    /// </summary> 
    IMongoCollection<Status> Statuses { get; set; } 

    /// <summary> 
    /// StatusGroup database context. 
    /// </summary> 
    IMongoCollection<StatusGroup> StatusGroups { get; set; } 

    /// <summary> 
    /// User database context. 
    /// </summary> 
    IMongoCollection<User> Users { get; set; } 

    /// <summary> 
    /// WorkArea database context. 
    /// </summary> 
    IMongoCollection<WorkArea> WorkAreas { get; set; } 

    /// <summary> 
    /// WorkCell database context. 
    /// </summary> 
    IMongoCollection<WorkCell> WorkCells { get; set; } 

    /// <summary> 
    /// Workorder database context. 
    /// </summary> 
    IMongoCollection<Workorder> Workorders { get; set; } 
} 

Neuer Fehler beim Eingabetyp Wechsel auf DeleteOneAsync UmIt.IsAny<FilterDefinition<Workorder>>()

Test Name: MESAPITests.RepositoryTests.WorkorderRepositoryTests.DeleteWorkorderById_ReturnsBooleanTrue 
Test FullName: MESAPITests.RepositoryTests.WorkorderRepositoryTests.DeleteWorkorderById_ReturnsBooleanTrue 
Test Source: C:\Users\Zacke\Documents\Repositories\MES-API\MES-API  Tests\RepositoryTests\WorkorderRepositoryTests.cs : line 21 
Test Outcome: Failed 
Test Duration: 0:00:00.283 

Result StackTrace: 
at MESAPI.Repositories.WorkorderRepository.<DeleteWorkorderById>d__2.MoveNext() in C:\Users\Zacke\Documents\Repositories\MES-API\MES-API\Repositories\WorkRepositories\WorkorderRepository.cs:line 28 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 
    at MESAPITests.RepositoryTests.WorkorderRepositoryTests.<DeleteWorkorderById_ReturnsBooleanTrue>d__1.MoveNext() in C:\Users\Zacke\Documents\Repositories\MES-API\MES-API Tests\RepositoryTests\WorkorderRepositoryTests.cs:line 33 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
Result Message: System.NullReferenceException : Object reference not set to an instance of an object. 

Picture: Hovering over result in the line above tells me it's null for some reason..

+1

Das Problem hier kann sein, dass die Überlastung der 'DeleteOneAsync' Sie verwenden (nämlich' Expression > 'ist eine statische Erweiterungsmethode, also nicht wirklich auf die "IMongoCollection" -Schnittstelle überhaupt, so dass das Setup nicht aufgerufen wird. Möglicherweise müssen Sie eine On-Interface-Überladung von 'DeleteOneAsync' [so] (http://mongodb.github.io/mongo-csharp-driver/ 2.4/apidocs/html/M_MongoDB_Driver_IMongoCollection_1_DeleteOneAsync_1.htm), oder wickeln Sie Mongo in Ihre eigene Schnittstellenabstraktion, wenn Sie Unit-Tests benötigen.Sie sollten auch 'void DeleteWorkorderById_ReturnsBooleanTrue' in eine Rückkehr' Task' ändern – StuartLC

+0

@StuartLC: Ich habe "FilterDefinition " statt der Ausdruck im obigen Beispiel verwendet, aber das gab mir den gleichen Fehler. Und stimmt über den Rückgabetyp, wird das ändern. –

+0

@ZackariasMontell Sie mischen auch blockierende Aufrufe '.Result' mit async erwarten in' WorkorderRepository', was zu Deadlocks führen kann. – Nkosi

Antwort

1

aktualisieren basierend auf Kommentare.

Moq kann Erweiterungsmethoden nicht vortäuschen und sollte direkt auf Mitgliedern der Schnittstelle ausgeführt werden, die verspottet werden.

IMongoCollection<TDocument>.DeleteOneAsync Method (FilterDefinition<TDocument>, CancellationToken) Method

mockCollection 
    .Setup(_ => _.DeleteOneAsync(It.IsAny<FilterDefinition<Workorder>>(), It.IsAny<CancellationToken>())) 
    .ReturnsAsync(new DeleteResult.Acknowledged(1)); 
+0

Ich habe das versucht, bevor ich die erste Zeile hinzugefügt habe, die du geschrieben hast. Es liefert das gleiche Ergebnis, soweit Fehler gehen. –

+0

Als Kommentar zu Ihrer Bearbeitung. Habe ich das nicht schon gemacht? Ich habe das CancellationToken von 'default (CancellationToken)' auf 'It.IsAny ()' geändert, aber das ändert nichts am Ergebnis für mich: /. Vielleicht verstehe ich nicht ganz, was Sie sagen .. –

Verwandte Themen