【问题标题】:Unit Testing WCF Service using Moq使用 Moq 对 WCF 服务进行单元测试
【发布时间】:2018-08-09 19:52:30
【问题描述】:

我一直在自学如何对应用程序的各个部分进行单元测试。我正在尝试对我的 UserService 进行单元测试。我似乎收到以下错误:

我不确定错误的含义。有人可以解释发生了什么吗?我知道该服务本身已经可以正常工作了,我已经单独对其进行了测试。我以前从未创建过单元测试,所以如果有人可以详细解释一下为什么会发生这种情况?

提前致谢!

用户服务测试

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);
    }
}

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

【问题讨论】:

  • 您在测试项目中是否引用了System.ServiceModel

标签: c# unit-testing wcf moq


【解决方案1】:

您似乎缺少对 System.ServiceModel 的引用

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

模拟的目标是在模拟依赖项的同时测试您的测试类。例如,如果您的 UserService 依赖于 UserRepository,您将模拟存储库以测试 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 设置为返回今天活跃的一位用户。 然后它调用 UserService 上的操作,并验证从未调用过 SendRemovalNotification。这将测试确定用户是否处于非活动状态的逻辑是否确实正确。

【讨论】:

  • 我明白了。这对我来说确实有点奇怪。我在网上找到了那个例子。你能给我一个如何做到这一点的例子吗?我确实有一个该服务正在调用的 UserRepository。感谢您的帮助。
  • 我添加了一个例子
  • 您忘记在构造函数中包含接口。因此,如果我想测试我的服务的 getallusers 函数,我会调用 userservice.getallusers() 并验证它是否等于 testUser。感谢您的帮助!
  • 我还必须模拟我的 unitofwork 界面...不确定如何在传入的上下文中做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 2010-09-07
  • 2023-03-16
  • 1970-01-01
  • 2011-12-24
相关资源
最近更新 更多