2016-10-12 71 views
2

我有一個像這樣的抽象工廠。使用Moq嘲諷具體類方法的返回值

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

而且我有它的具體實現。

public class SyncFactory : AbstractFactory 
{ 
    private readonly IOperatorRepository _operatorRepository; 

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

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

這個混凝土工廠是用這種方法訪問的。

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

現在我需要爲MethodTobeTested()編寫一個單元測試。

我像這樣嘲笑了GetSyncService()的返回值。但它調用的是實際的OperatorSyncService,而不是模擬。我需要這個模擬嘲笑裏面OperatorSyncService

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

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

另一種方法就如何解決這個任何想法?

+2

爲什麼不簡單地模擬IOperatorRepository並調用方法 – ChrisBint

+0

'MethodToBeTested'與'SyncFactory'緊密耦合,因爲該方法手動創建'SyncFactory'的新實例。這使得嘲笑依賴非常困難。 – Nkosi

回答

2

在您的SyncFactory實現中,您將注入一個IOperatorRepository實例。這非常棒,因爲它允許您在需要時插入不同的版本,併爲您創建一個似乎讓您使用IOperatorRepository的模擬實現。

你也做了一個抽象工廠,看起來不錯,但看起來問題在於你對工廠的使用;

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

在你MethodToBeTested您創建一個具體的實施SyncFactory的,這使抽象工廠的點一點redundent因爲你不能注入不同的實現。我不知道你在哪裏創建_operatorRepository實例,但我可以看到兩種方式。

  1. 在包含MethodToBeTested添加一個參數是需要你的抽象工廠的實例類的構造函數,然後讓你的MethodToBeTested使用此注射,而不是創建一個新的工廠,這將讓你嘲笑整個工廠 - 這是我推薦的方法,因爲包含MethodToBeTested的類將不再需要知道如何創建工廠實例,如果遵循單一職責原則,則不應該這樣做。不會有任何具體實施依賴。

  2. 與上面相反,但是注入IOperatorRepository而不是工廠,然後可以注入一個模擬IOperatorRepository,但我建議不要這樣做,因爲您已經完成了創建所有抽象的工作,然後將此工作放在一邊, 「新達」 syncFactory的實例,並在方法MethodTobeTested創建一個具體的依賴

+0

第一種選擇顯然是有用的和有見地的。謝謝!!! – Prasadi

0

new創建新實例,所以沒有模擬可以注射。注入工廠,例如作爲參數,所以它可以在測試中被嘲笑。

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是緊耦合到SyncFactory,因爲該方法是手動創建的SyncFactory的新實例。這使得嘲笑依賴非常困難。

假設

public class ClassToBeTested { 

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

} 

ClassToBeTested需要重構到

public class ClassToBeTested { 
    private readonly AbstractFactory syncFactory; 

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

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

} 

這將允許被嘲笑的依賴性並注入類待測試以及由該方法訪問,以進行測試。現在要測試的類只需要知道它需要知道什麼。現在不再需要知道IOperatorRepository

+0

這是工作。謝謝!!! – Prasadi