如何在 moq 中为属性赋值?

我有一个类,它的方法返回 User类型的对象

public class CustomMembershipProvider : MembershipProvider
{
public virtual User GetUser(string username, string password, string email, bool isApproved)
{
return new User()
{
Name = username
,Password = EncodePassword(password)
,Email = email
,Status = (isApproved ? UsuarioStatusEnum.Ativo : UsuarioStatusEnum.ConfirmacaoPendente)
// ...
};
}


// ..
}

User是一个域对象。请注意 塞特受到保护Id属性:

public class User : IAuditable, IUser
{
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
public virtual string Email { get; set; }
public virtual UsuarioStatusEnum Status { get; set; }
public virtual string Password { get; set; }
}

Id 受到保护,因为它是由数据库生成的。

测试项目

在我的 Test 项目中,我有一个 Fake 存储库,它使用 Store方法来保存/更新对象:

public void Store(T obj)
{
if (obj.Id > 0)
_context[obj.Id] = obj;
else
{
var generateId =  _context.Values.Any() ? _context.Values.Max(p => p.Id) + 1 : 1;
var stubUser = Mock.Get<T>(obj); // In test, will always mock
stubUser.Setup(s => s.Id).Returns(generateId);
_context.Add(generateId, stubUser.Object);
}
}

CustomMembershipProvider中,我有一个 public override MembershipUser CreateUser方法,它调用 GetUser来创建一个 User
这样,我所要做的就是模拟 GetUser方法,这样存储库就可以生成 Id

var membershipMoq = new Mock<CustomMembershipProvider>();
membershipMoq.CallBase = true;
membershipMoq
.Setup(p => p.GetUser(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
.Returns<string, string, string, bool>( (username, password, email, isAproved) => {
var moqUser = new Mock<User>();
moqUser.Object.Name = username;
moqUser.Object.Password = password;
moqUser.Object.Email = email;
moqUser.Object.Status = (isAproved ? UsuarioStatusEnum.Ativo : UsuarioStatusEnum.ConfirmacaoPendente);
return moqUser.Object;
});
_membershipProvider = membershipMoq.Object;

问题

理论上一切都是正确的。当 CreateUser调用‘ GetUser’来创建一个用户时,用户将返回模拟填充;

[TestMethod]
public void CreateUser_deve_criar_usuario_no_repositorio()
{
// Act
MembershipCreateStatus status;
var  usr = _membershipProvider.CreateUser(
_fixture.Create<string>(),
_fixture.Create<string>(),
_fixture.Create<string>(),
null, null, true, null,
out status);


// usr should have name, email password filled. But not!


// Assert
status.Should().Be(MembershipCreateStatus.Success);
}

问题是电子邮件,名称,密码是空的(默认值) !

enter image description here

85043 次浏览

我认为你错过了嘲笑的目的。嘲笑用来嘲笑你正在测试的类的依赖性:

enter image description here

接受测试的系统(SUT)应隔离测试(即与其他单元分开测试)。否则,依赖项中的错误将导致 SUT 测试失败。此外,不应为模拟编写测试。这将一无所获,因为模拟不是生产代码。在应用程序中不执行模拟。

因此,只有在测试某个依赖于它的单元时,才应该模仿 CustomMembershipProvider(顺便说一句,最好创建一些抽象,比如依赖于接口 ICustomMembershipProvider)。

或者,如果您正在为 CustomMembershipProvider类编写测试,则不应对其进行模拟-只应模拟此提供程序的依赖项。

准备模拟用户的方式是问题所在。

moqUser.Object.Name = username;

将不会设置名称,除非您已经正确设置了模拟。 在为属性分配值之前尝试这样做:

moqUser.SetupAllProperties();

此方法将准备模拟上的所有属性,以便能够记录分配的值,并在以后重播(即充当真实属性)。

还可以使用 SetupProperty ()方法设置单个属性,以便能够记录传入的值。

另一种方法是:

var mockUser = Mock.Of<User>( m =>
m.Name == "whatever" &&
m.Email == "someone@example.com");


return mockUser;

指定模拟上的所有属性应具有“属性行为”, 这意味着设置它们的值将导致保存它们,并在请求属性时返回它们。 (这也被称为“撞击”。) 每个属性的默认值将是 属性。

mock.SetupAllProperties();