在两个不同的方法上使用Mock.Setup并不匹配一个而是返回null

时间:2016-01-07 12:52:50

标签: asp.net-mvc unit-testing moq

我是单元测试的新手。我正在使用Moq进行单元测试。我有一种情况,我必须在同一部分模拟两种不同的方法:

我有一个如下所示的行动方法:

public ActionResult Login(someparameters)
{
   //code...
  var user = userRepository.SelectAllUserByEmail(someparamters); //first method
  //....
  var userDetails = userRepository.ValidateUser(someparameters);//second method
}

这是我的单元测试部分:

userrepositoryMock.Setup(r => r.SelectAllUserByEmail(someparameters))
  .Returns(new List<User>() { new User { Salt = strSalt, FundraiserAdminId = fundadmind, StatusCode = statusCode, UserTypeId = userTypeId, HomePageURL = homepageURL, OrganizationId = organizationId } } );

userrepositoryMock.Setup(k => k.ValidateUser(someparamters))
.Returns(new User { Salt = strSalt, FundraiserAdminId = fundadmind, StatusCode = statusCode, UserTypeId = userTypeId, HomePageURL = homepageURL, OrganizationId = organizationId });

但是这只会SelectAllUserByEmail ValidateUser方法,它会返回null。

2 个答案:

答案 0 :(得分:2)

您还没有指定someparameters代表什么类型(或类型),但我敢打赌,其中至少有一种是引用类型(不是简单的字符串)。

对于引用类型(如对象实例),在精确实例上使用Moq&#39; .Setup通常是一个坏主意,因为这将要求完全相同的引用按顺序传递给模拟类使安装程序匹配并返回提供的输出。

这是一个简单的MVCE,可以再现问题。给出以下代码:

public class User
{
    public string Name { get; set; }
}

public interface IMyInterface
{
    string GetUserName(User user);
}

以下单元测试表明,如果传递了另一个引用(Setup),绑定到特定对象实例(aUser)的sameUser NOT 匹配到模拟:

[Test]
public void TestGetUserBad()
{
    var mock = new Mock<IMyInterface>();

    var aUser = new User { Name = "User1" };
    var sameUser = new User { Name = "User1" };

    mock.Setup(x => x.GetUserName(aUser)).Returns<User>(u => u.Name);

    Assert.AreEqual("User1", mock.Object.GetUserName(aUser), 
        "The mock has been setup for aUser, so this works");
    Assert.AreEqual(null, mock.Object.GetUserName(sameUser), 
        "aUser is a different reference than sameUser hence fails");
}

相反,您应该使用Moq的It.Is<>(带谓词)或It.IsAny<>(任意)matchers来匹配任何符合谓词的引用(如果有的话) )。

[Test]
public void TestGetUserGood()
{
    var mock = new Mock<IMyInterface>();

    var aUser = new User { Name = "User1" };
    var sameUser = new User { Name = "User1" };

    mock.Setup(x => x.GetUserName(It.IsAny<User>())).Returns<User>(u => u.Name);

    Assert.AreEqual("User1", mock.Object.GetUserName(aUser), 
        "The mock has been setup for any user, so this works");
    Assert.AreEqual("User1", mock.Object.GetUserName(sameUser), 
        "The mock has been setup for any user, so this works");
}

修改

出于兴趣,如果您怀疑您的某个模拟设置未按预期匹配(如果未找到匹配项,则使用松散模拟时Moq将返回default(T)),您可以暂时切换{ {3}},如果设置不匹配,则会抛出。

e.g。将以下内容应用于TestGetUserBad

var mock = new Mock<IMyInterface>(MockBehavior.Strict);

结果:

  

Moq.MockException:IMyInterface.GetUserName(User)调用因模拟行为Strict而失败。模拟上的所有调用都必须有相应的设置。

答案 1 :(得分:0)

我通过添加以下代码解决了这个问题:

 userrepositoryMock.SetReturnsDefault(new User { Salt = strSalt, FundraiserAdminId = fundadmind, StatusCode = statusCode, UserTypeId = userTypeId, HomePageURL = homepageURL, OrganizationId = organizationId });