2016-10-12 6 views
2

Ich habe eine abstrakte Fabrik wie diese.Verspotten Rückgabewerte einer konkreten Klassenmethode mit Moq

public abstract class AbstractFactory 
{ 
    public abstract ISyncService GetSyncService(EntityType entityType); 
} 

Und ich habe seine konkrete Implementierung so.

public class SyncFactory : AbstractFactory 
{ 
    private readonly IOperatorRepository _operatorRepository; 

    public SyncFactory(IOperatorRepository operatorRepository) 
    { 
     _operatorRepository = operatorRepository; 
    } 

    public override ISyncService GetSyncService(EntityType entityType) 
    {    
      return new OperatorSyncService(_operatorRepository);   
    } 
} 

Diese Betonfabrik wird in einer solchen Methode aufgerufen.

public void MethodTobeTested() 
{ 
    var syncService = 
       new SyncFactory(_operatorRepository).GetSyncService(entityType); 
} 

Jetzt muss ich einen Komponententest für MethodTobeTested() schreiben.

Ich verspottete den Rückgabewert der GetSyncService() wie folgt. Aber es ruft den tatsächlichen OperatorSyncService auf, nicht den Schein. Ich brauche diesen Schein, um eine andere Methode im OperatorSyncService zu verspotten

private Mock<SyncFactory> _syncServiceMock; 
_syncServiceMock = new Mock<SyncFactory>(); 

_syncServiceMock.Setup(m => m.GetSyncService(operator)).Returns(_operatorSyncServiceMock.Object); 

Irgendeine Idee, wie man das löst?

+2

Warum nicht einfach IoperatorRepository abspotten und die Methode aufrufen – ChrisBint

+0

'MethodToBeTested' ist eng an' SyncFactory' gekoppelt, weil die Methode manuell eine neue Instanz von 'SyncFactory' erstellt. Dies macht es sehr schwierig, die Abhängigkeit zu verspotten. – Nkosi

Antwort

2

In Ihrer SyncFactory-Implementierung injizieren Sie eine Instanz von IOperatorRepository. Das ist großartig, weil es Ihnen erlaubt, eine andere Version zu injizieren, wenn es notwendig ist, und es schafft, dass Sie eine Scheinimplementierung von IOperatorRepository verwenden.

Sie haben auch eine abstrakte Fabrik gemacht, die gut aussieht, aber es sieht so aus, als ob das Problem bei Ihrer Nutzung der Fabrik liegt;

var syncService = 
      new SyncFactory(_operatorRepository).GetSyncService(entityType); 

In Ihrem MethodToBeTested Sie eine konkrete Umsetzung SyncFactory schaffen, das den Punkt der abstrakten Fabrik machen ein wenig redundent, da Sie nicht eine andere Implementierung injizieren kann. Ich weiß nicht, wo Sie Ihre _operatorRepository-Instanz finden, aber ich kann zwei Möglichkeiten sehen.

  1. Im Konstruktor der Klasse, die enthält MethodToBeTested einen Parameter hinzuzufügen, die eine Instanz der abstrakten Fabrik nimmt, dann erhalten Sie Ihre MethodToBeTested diese Fabrik injiziert zu verwenden, anstatt eine neue zu erstellen, würde dies erlauben Sie zu verspotten Die gesamte Factory - das ist mein empfohlener Ansatz, da die Klasse, die MethodToBeTested enthält, nicht mehr wissen muss, wie eine Factory-Instanz erstellt wird. Dies sollte nicht der Fall sein, wenn Sie dem Prinzip der einheitlichen Verantwortlichkeit folgen. Es würde keine Abhängigkeit von einer konkreten Umsetzung geben.

  2. Wie oben, aber stattdessen IoperatorRepository anstelle der Fabrik injizieren, können Sie dann ein Mock IOperatorRepository injizieren, aber ich würde davon abraten, da Sie eine so gute Arbeit gemacht haben, alle Ihre Abstraktionen zu erstellen, um diese Arbeit beiseite zu legen und „neue up“ eine Instanz von syncFactory und einer Beton Abhängigkeit

+0

Die erste Option war offensichtlich nützlich und aufschlussreich. Vielen Dank!!! – Prasadi

0

new die bei dem Verfahren MethodTobeTested schafft neue Instanz erstellen, so kann keine mock injiziert werden. Injizieren Sie die Fabrik z.B. als Parameter, so kann es im Test verspottet werden.

public void MethodTobeTested(AbstractFactory factory) 
{ 
    EntityType entityType = null; 
    var syncService = factory.GetSyncService(entityType); 
} 

[TestMethod] 
public void Method_Condition_Result() 
{ 
    // Arrange 
    TestedClass tested = new TestedClass(); 
    Mock<ISyncService> syncServiceMock = new Mock<ISyncService>(); 
    Mock<AbstractFactory> factoryMock = new Mock<AbstractFactory>(); 
    factoryMock.Setup(f => f.GetSyncService(It.IsAny<EntityType>())).Returns(syncServiceMock.Object); 

    // Act 
    tested.MethodTobeTested(factoryMock.Object); 

    // Assert 
    // ... 
} 
1

MethodToBeTested ist eng gekoppelt SyncFactory, da das Verfahren von Hand wird eine neue Instanz von SyncFactory erzeugen. Dies macht es sehr schwierig, die Abhängigkeit zu verspotten.

public class ClassToBeTested { 

    public void MethodTobeTested() { 
     var syncService = new SyncFactory(_operatorRepository).GetSyncService(entityType); 
     //...other code 
    } 

} 

ClassToBeTested Unter der Annahme, sollte

public class ClassToBeTested { 
    private readonly AbstractFactory syncFactory; 

    public ClassToBeTested (AbstractFactory factory) { 
     this.syncFactory = factory 
    } 

    public void MethodTobeTested() { 
     var syncService = syncFactory.GetSyncService(entityType); 
     //...other code 
    } 

} 

Dies ermöglicht die Abhängigkeit zu verspottet und injiziert in die Klasse

refactored werden nach dem Verfahren getestet und die zugegriffen werden soll getestet werden. Die zu testende Klasse muss jetzt nur noch wissen, was sie wissen muss. Es muss jetzt nicht mehr beachtet werden IOperatorRepository.

+0

Das funktioniert. Vielen Dank!!! – Prasadi

Verwandte Themen