代码之家  ›  专栏  ›  技术社区  ›  Eric Obermuller

使用Moq对WCF服务进行单元测试

  •  1
  • Eric Obermuller  · 技术社区  · 7 年前

    我一直在自学如何对应用程序的各个部分进行单元测试。我正在尝试对我的用户服务进行单元测试。我似乎得到了以下错误: User Service Error

    我不知道这个错误意味着什么。有人能解释一下发生了什么事吗?我知道服务本身已经工作了,我已经分别测试过了。我以前从来没有创建过单元测试,所以如果有人能给我一个详细的解释,为什么会这样?

    提前谢谢!

    用户服务测试

    public class UserServiceTest
    {
        public readonly IUserService MockUserService;
    
    
        public List<UserDTO> userDTOList = new List<UserDTO>
        {
            new UserDTO(new User{UserId = 1, FirstName = "Eric"}),
            new UserDTO(new User{UserId = 1, FirstName = "Dave"}),
            new UserDTO(new User{UserId = 1, FirstName = "Jim"})
    
        };
    
        public UserServiceTest()
        {
            Mock<IUserService> mockUserService = new Mock<IUserService>();
    
            mockUserService.Setup(mr => mr.GetAllUsers()).Returns(userDTOList);
            this.MockUserService = mockUserService.Object;
    
        }
    
        [TestMethod]
        public void TestServiceGetUsers()
        {
            List<UserDTO> testUserList = this.MockUserService.GetAllUsers();
    
            Assert.IsNotNull(testUserList);
            Assert.AreEqual(userDTOList, testUserList);
        }
    }
    

    WCF接口

     [ServiceContract]
    public interface IUserService
    {
        [OperationContract]
        List<UserDTO> GetAllUsers();
    
    }
    
    [DataContract]
    
    public class UserDTO
    {
        public UserDTO(User user)
        {
            this.FirstName = user.FirstName;
            this.LastName = user.LastName;
            this.NumberOfItemsSold = user.NumberOfItemsSold;
            this.UserId = user.UserId;
            this.UserName = user.UserName;
    
        }
    
        [DataMember]
        public int UserId { get; set; }
    
        [DataMember]
        public string FirstName { get; set; }
    
        [DataMember]
        public string LastName { get; set; }
    
        [DataMember]
        public string UserName { get; set; }
    
        [DataMember]
        public int NumberOfItemsSold { get; set; }
    }
    

    WCF接口实现

    public class UserService : IUserService
    {
        public List<UserDTO> GetAllUsers()
        {
            using (UnitOfWork work = new UnitOfWork(new ProductContext()))
            {
    
                return work.Users.GetAll().Select(a => new UserDTO(a)).ToList();
            }
        }
    }
    

    根据Mel Gerats的建议进行编辑

    好的,所以我想我应该为我的单元测试放一个更新的代码,它现在实际测试服务。给你!再次感谢你的帮助。

    [TestClass]
    public class UserServiceTest
    {
    
        public List<UserDTO> userDTOList = new List<UserDTO>
        {
            new UserDTO(new User{UserId = 1, FirstName = "Eric"}),
            new UserDTO(new User{UserId = 2, FirstName = "Dave"}),
            new UserDTO(new User{UserId = 3, FirstName = "Jim"})
    
        };
    
        public IEnumerable<User> users = new List<User>
        {
            new User{UserId = 1, FirstName = "Eric"},
            new User{UserId = 2, FirstName = "Dave"},
            new User{UserId = 3, FirstName = "Jim"}
        };
    
        [TestMethod]
        public void TestServiceGetUsers()
        {
            //Setup
            var unitOfWorkMock = new Mock<IUnitOfWork>();
            unitOfWorkMock.Setup(m => m.Users.GetAll()).Returns(users);
    
            var serviceUnderTest = new UserService(unitOfWorkMock.Object);
    
    
    
            var result = serviceUnderTest.GetAllUsers();
    
            Assert.IsNotNull(result);
    
            Assert.AreEqual(userDTOList.Count, result.Count);
            Assert.AreEqual(userDTOList[0].FirstName, result[0].FirstName);
            Assert.AreEqual(userDTOList[1].FirstName, result[1].FirstName);
        }
    }
    

    出于某种原因,我无法直接测试这两个列表是否相等。我想是因为我的单子上单子的容量不同。所以我选择测试列表中的每个位置。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Mel Gerats    7 年前

    你好像少了一个 System.ServiceModel

    但是您的测试实际上并没有测试任何东西,除了可能模拟工作之外,因为您只是在模拟上调用模拟方法。

    模拟的目标是在模拟依赖项的同时测试被测试的类。例如,如果您的UserService依赖于一个UserRepository,那么您可以模拟这个repository来测试UserService。

    以下示例说明了这一点:

    public class UserService : IUserService
    {
        private IUserRepository _userRepository;
        private IUserNotification _userNotification;
    
        public UserService(IUserRepository userRepository, IUserNotification userNotification)
        {
            _userRepository = userRepository;
            _userNotification = userNotification;   
        }
    
        public void NotifyInactiveUsers(DateTime activeBefore)
        {
            var users = _userRepository.GetAllUsers();
            foreach(var user in users)
            {
                if(user.LastActivityDate > DateTime.Now)
                {
                    _userNotification.SendRemovalNotification(user)
                    _userRepository.MarkUserForRemoval(user)
                }
            }
        }
    }
    

    UserService提供一个操作,通知自给定日期以来处于非活动状态的所有用户。

    public void TestUserService_NotifyInactiveUsers_BeforeActivityDate()
    {
        var userRepository = new Mock<IUserRepository>();
        var userNotification = new Mock<IUserNotification>();
        var userService = new UserService(userRepository.Object, userNotification.Object);
    
        var testUser = new User { LastActivityDate = DateTime.Now}
        userRepository.Setup(r => r.GetAllUsers()).Returns(Enumerable.Repeat(testUser, 1));
    
        userService.NotifyInactiveUsers(DateTime.Now.AddYears(-1));
    
        userNotification.Verify(n => n.SendRemovalNotification(It.IsAny<User>), Times.Never);
    }
    

    测试设置UserRepository以返回一个今天处于活动状态的用户。 然后它调用用户服务上的操作,并验证是否从未调用SendRemovalNotification。这将测试确定用户是否处于非活动状态的逻辑是否确实正确。