我有一个类,其方法返回类型为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
是一个域对象。请注意 setter as protected 的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项目中,我有一个带有方法Store
的Fake存储库来保存/更新对象:
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);
}
问题是电子邮件,姓名,密码为空(默认值为)!
答案 0 :(得分:97)
准备模拟用户的方法就是问题。
moqUser.Object.Name = username;
除非您正确设置了模拟,否则不会设置名称。 在为属性赋值之前尝试此操作:
moqUser.SetupAllProperties();
此方法将准备模拟的所有属性,以便能够记录指定的值,并在以后重播(即充当不动产)。
您还可以使用 SetupProperty()方法设置单个属性,以便能够记录传入的值。
另一种方法是:
var mockUser = Mock.Of<User>( m =>
m.Name == "whatever" &&
m.Email == "someone@example.com");
return mockUser;
答案 1 :(得分:7)
我认为你缺少嘲笑的目的。模拟用于模拟您正在测试的类的依赖项:
待测系统(SUT)应单独测试(即与其他单元分开)。否则,依赖项中的错误将导致SUT测试失败。你也不应该为模拟编写测试。这没有给你什么,因为模拟不是生产代码。模拟不会在您的应用程序中执行。
所以,你应该模拟CustomMembershipProvider
只有你正在测试一些单元,这取决于它(BTW最好创建一些抽象,如接口ICustomMembershipProvider
依赖)。
或者,如果您正在为CustomMembershipProvider
类编写测试,那么不应该对其进行模拟 - 只应该模拟此提供程序的依赖项。
答案 2 :(得分:0)
指定模拟上的所有属性都应该具有“属性行为”, 这意味着设置它们的值将导致它们被保存并稍后在请求属性时返回。 (这也称为“存根”。) 每个属性的默认值将是由 模拟的属性。
mock.SetupAllProperties();