0

我开始对单元测试进行一些实验,以便我们可以将它们包含在我们的领域层中。但是我不知道我是否走在正确的道路上,因此我将解释我目前正在做什么,看看我是否走在正确的轨道上。基本上架构如下所示,域层包含域模型和域服务(例如,用户类和用户服务类)。然后域层与实现通用存储库模式和工作单元的 DAL 通信。它的构造函数中的每个域服务类都接受一个 IUnitOfWork 接口,如下所示:

    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)

任何反馈将不胜感激。谢谢!

4

1 回答 1

0

我认为您的原始(第二个,在问题中)测试失败_unitOfWork.UserRepository了,因为nullInitialize. 通常 FakeItEasy 会在使用链式属性时创建一个假对象,但我猜测(我必须猜测,因为我对 的类型一无所知UserRepository)该类型是不可伪造的。在这种情况下,您会从.UserRepository_unitOfWork.UserRepository

让我跳回到你的第二个测试(这是你问题中的第一个),然后我们将回到我认为你可能想要在这里做的事情。

看着你的测试,

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

我看到了一个缺陷。您正在_userService直接调用一个方法,但_userService它是一个假对象,因此测试实际上不涉及任何生产代码。真的只是在锻炼 FakeItEasy。

我认为我们想要的是一种混合方法 - 可以真实地执行代码UserService,而无需担心UserRepository。也许类似于(而且我在这里没有使用编译器,也不知道正在使用什么方法,IUnitOfWork所以对此持保留态度)

[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除了 之外没有任何用处UserRepository,那么我认为下一步将调查为什么该类型UserRepository是不可伪造的(如果我的猜测是正确的)——它是密封的吗?它是否缺少适当且可访问的构造函数?

于 2013-12-11T15:44:37.673 回答