2015-06-09 72 views
2

問題

我們有一個使用FromServicesAttribute填充的控制器屬性。測試使用FromServicesAttribute填充的屬性

[FromServices] 
public IGenericRepository<TodoItem> TodoItemRepository { get; } 

我們要使用此屬性進行測試。我們如何嘲笑它?例如,如果我們使用構造函數注入,我們可以將模擬實現傳遞給構造函數。我們如何以這種方式對待財產?

我們當前的方法

這是怎麼了,我們目前正與Moq這樣做。

[Fact] 
public void GetAll_GetsCollection() 
{ 
    // setup mock repository 
    var all = new List<TodoItem>() 
    { 
     new TodoItem(), 
     new TodoItem(), 
     new TodoItem() 
    };    

    var mockRepo = new Mock<IGenericRepository<TodoItem>>(); 
    mockRepo.Setup(x => x.All()).Returns(all); 

    // setup mock unit of work 
    // including what the [FromService] property will return 
    var mockUnitOfWork = new Mock<IUnitOfWork>(); 
    mockUnitOfWork 
     .Setup(x =>x.TodoItemRepository) 
     .Returns(mockRepo.Object); 

    // test controller 
    TodoController controller = new TodoController(mockUnitOfWork.Object); 
    var result = controller.GetAll(); 
    Assert.Equal(3, result.Count()); 
} 

這是行不通的,並通過測試。也許它夠好。我們是TDD的新手。

+1

您是否使用'FromServices'而不是施工注入,因爲該服務並未被控制器上的所有操作使用?如果是的話,我更喜歡使用存儲庫作爲參數上的'FromServices'裝飾的行動... MVC特別處理'FromServices'裝飾參數...這是它有一個模型活頁夾...它作爲一個參數很明顯,一個行動取決於一個服務,使其更好的單元測試.. –

回答

5

使屬性可設置(內部如果需要)並使用InternalsVisibleTo使測試儀對測試組件可見。然後,在測試代碼中構造對象後,設置該屬性。

或者,如果您在測試代碼中使用DI,則創建一個假的IGenericRepository<TodoItem>並讓DI容器注入它。

+0

我真的很感興趣,我們可以創建一個虛假的'IGenericRepository ',然後*讓DI容器注入它。當我們通過單元測試運行時,我們怎麼能讓DI容器注入它?目前,我們在我們正在測試的項目的Startup.cs類中配置我們的DI容器。例如,我們是否使用了另一個在我們的測試項目中的Startup.cs,在那裏配置了DI容器?換句話說,在我們的單元測試項目中設置DI容器? –

+2

'FromServices'修飾的屬性在動作調用之前的ModelBinding階段被賦值。那就是在模型綁定階段,MVC從DI獲得服務併爲屬性賦值(並且如Victor所述,您需要爲您的屬性設置一個setter,否則MVC將無法爲該屬性賦值)。因此,對於這種情況,即使您爲單元測試設置了DI容器,您的屬性也不會被填充,因爲您只是單元測試控制器,並且沒有模型綁定階段。續... –

+1

無論如何,您爲單元測試分配DI容器的方式如下:https://github.com/aspnet/MusicStore/blob/master/test/MusicStore.Test/StoreControllerTest.cs#L20 -L26 –