2013-12-11 57 views
0

我開始做一些單元測試的實驗,以便我們可以將它們包含在我們的域層中。但是我不知道我是否遵循正確的道路,因此我要解釋我目前正在做的事情,看看我是否在正確的軌道上。基本上這個體系結構就像下面的域層包含域模型和域服務(例如User類和UserService類)。然後域層與實現通用存儲庫模式的DAL一起與工作單元進行通信。在它的構造函數中的每個域服務類接受一個I​​UnitOfWork界面,如下所示:FakeIt易於測試域服務+ UnitOfWork

public class UserService: IUserService 
    { 
     private readonly IUnitOfWork _unitOfWork; 

     public UserService(IUnitOfWork unitOfwork) 
     { 
      this._unitOfWork = unitOfwork; 
     } 

    } 

爲了創造單元測試,我決定去與FakeItEasy框架。所以在一個UserServiceTest類我做了以下事情: -

private IUserService _userService; 
    private const int userID = 2013; 

    [TestInitialize] 
    public void Initialize() 
    { 
    _userService = A.Fake<IUserService>(); 

     A.CallTo(() => _userService.GetUserById(userID)).Returns(new User 
      { 
       UserID = userID, 
       RegistrationDate = DateTime.Now, 
      }); 
    } 


    [TestMethod] 
    public void GetUserByID() 
    { 
     var user = _userService.GetUserById(userID); 
     Assert.IsInstanceOfType(user, typeof(Domain.User)); 
     Assert.AreEqual(userID, user.userID); 
    } 

當我運行測試時,它們通過。這是實施單元測試的正確方法嗎?在我嘗試一種不同的方法之前,FakeItEasy因ProxyGenerator異常而失敗。我在做什麼,這是: -

[TestInitialize] 
public void Initialize() 
{ 
_unitOfWork = A.Fake<IUnitOfWork>(); 

A.CallTo(() => _unitOfWork.UserRepository.FindById(userID)).Returns(new UserDto 
    { 
     UserID = userID, 
     RegistrationDate = DateTime.Now, 
    }); 


AutoMapper.Mapper.CreateMap<UserDto, User(); 
} 

[TestMethod] 
public void GetUserByID() 
{ 
    var userService = new UserService(_unitOfWork); 
    var user = userService.GetUserById(userID); 
    Assert.IsInstanceOfType(user, typeof(Domain.User)); 
    Assert.AreEqual(userID, user.userID); 
} 

,這是拋出異常如下: -

Result Message: 
Initialization method Initialize threw exception. System.ArgumentNullException: System.ArgumentNullException: Value cannot be null. 
Parameter name: callTarget. 
Result StackTrace: 
at FakeItEasy.Creation.ProxyGeneratorSelector.MethodCanBeInterceptedOnInstance(MethodInfo method, Object callTarget, String& failReason) 
    at FakeItEasy.Configuration.DefaultInterceptionAsserter.AssertThatMethodCanBeInterceptedOnInstance(MethodInfo method, Object callTarget) 
    at FakeItEasy.Configuration.FakeConfigurationManager.AssertThatMemberCanBeIntercepted(LambdaExpression callSpecification) 
    at FakeItEasy.Configuration.FakeConfigurationManager.CallTo[T](Expression`1 callSpecification) 
    at FakeItEasy.A.CallTo[T](Expression`1 callSpecification) 

任何反饋將不勝感激。謝謝!

+0

你的'UserService'看起來像存儲庫。我會將它們視爲DAL的一部分。當Domain Model知道抽象「IUnitOfWork」,但你的域名服務與[Big Blue Book](http:// dddcommunity)中的描述不同時,org/book/evans_2003 /)([域驅動設計中的服務](http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/),[Services in Domain-Driven Design](http://lostechies.com/jimmybogard/2008/08/21/services-in-domain-driven-design/))。 –

回答

0

我認爲您的原件(第二個,在問題中)測試失敗,因爲_unitOfWork.UserRepositoryInitialize中返回爲null。通常FakeItEasy會在使用鏈式屬性時創建假對象,但我猜測(我必須猜測,因爲我不知道UserRepository的類型)UserRepositorytype is not fakeable。在這種情況下,你會從_unitOfWork.UserRepository得到一個空回。

讓我回到你的第二個測試(這是你的第一個問題),然後我們會回到我認爲你可能想在這裏做的事情。

看你的測試,

var user = _userService.GetUserById(userID); 
Assert.IsInstanceOfType(user, typeof(Domain.User)); 
Assert.AreEqual(userID, user.userID); 

我看到一個缺陷。您直接在_userService上調用方法,但_userService是假對象,因此該測試實際上不涉及任何生產代碼。它只是在執行FakeItEasy。

我想我們想要的是一種混合的方法 - 這將在真正的UserService中執行代碼,而不用擔心UserRepository。也許類似的東西

[TestInitialize] 
public void Initialize() 
{ 
    _unitOfWork = A.Fake<IUnitOfWork>(); 
    A.CallTo(() => _unitOfWork.GetUserById(userID)) 
     .Returns(new User 
     { 
      UserID = userID, 
      RegistrationDate = DateTime.Now, 
     }); 
} 

[TestMethod] 
public void GetUserByID() 
{ 
    var userService = new UserService(_unitOfWork); 
    var user = userService.GetUserById(userID); 
    Assert.IsInstanceOfType(user, typeof(Domain.User)); 
    Assert.AreEqual(userID, user.userID); 
} 

或者,(我沒有使用編譯器在這裏,不知道是在什麼IUnitOfWork方法,以便用一粒鹽藉此),如果沒有什麼有用的上IUnitOfWork除了UserRepository,那麼我認爲下一步將調查爲什麼UserRepository的類型不是假的(如果我的猜測是正確的) - 它是密封的嗎?它缺乏適當和可訪問的構造函數嗎?