【发布时间】:2016-09-13 10:07:57
【问题描述】:
我以前从未使用 Moq 来模拟上下文,而且我很确定这很容易做到,因为我有一些 RhinoMock 的经验。 但是当我尝试做简单的事情时,使用 UnitTest 检查对象是否正确创建时,我没有得到预期的结果。
假设我有一个用户实体,其中包含一些数据。这是用户类:
public string UserName { get; set; }
public string Password { get; set; }
public Person Person { get; set; }
public List<Role> Roles { get; set; }
public ISecurityService SecurityService { get; set; }
public byte[] Salt { get; set; }
public User(string userName, string password, Person person, ISecurityService securityService)
{
UserName = userName;
Person = person;
Roles = new List<Role>();
SecurityService = new SecurityService();
Salt = securityService.GenerateSalt(4);
Password = securityService.GenerateHashedAndSaltedPassword(password, Salt);
}
我在创建用户时为我的密码使用了加盐和散列。方法GenerateSalt(int salt) 和GeneraHasedAndSaltedPassword(stiring password, byte[] salt) 是SecurityService 类的一部分。这就是我实现类的方式:
我有ISecurityService接口:
public interface ISecurityService
{
byte[] GenerateSalt(int saltSize);
string GenerateHashedAndSaltedPassword(string password, byte[] salt);
}
SecurityService 类正在实现该接口:
public class SecurityService : ISecurityService
{
string ISecurityService.GenerateHashedAndSaltedPassword(string password, byte[] salt)
{
HashAlgorithm algorithm = new SHA1Managed();
var plainTextBytes = Encoding.ASCII.GetBytes(password);
var plainTextWithSaltBytes = AppendByteArray(plainTextBytes, salt);
var saltedSHA1Bytes = algorithm.ComputeHash(plainTextWithSaltBytes);
var saltedSHA1WithAppendedSaltBytes = AppendByteArray(saltedSHA1Bytes, salt);
return "{SSHA}" + Convert.ToBase64String(saltedSHA1WithAppendedSaltBytes);
}
byte[] ISecurityService.GenerateSalt(int saltSize)
{
var rng = new RNGCryptoServiceProvider();
var buff = new byte[saltSize];
rng.GetBytes(buff);
return buff;
}
private byte[] AppendByteArray(byte[] byteArray1, byte[] byteArray2)
{
var byteArrayResult =
new byte[byteArray1.Length + byteArray2.Length];
for (var i = 0; i < byteArray1.Length; i++)
byteArrayResult[i] = byteArray1[i];
for (var i = 0; i < byteArray2.Length; i++)
byteArrayResult[byteArray1.Length + i] = byteArray2[i];
return byteArrayResult;
}
}
在我的单元测试中,我有 Init() 方法:
[SetUp]
public void Init()
{
var securityServiceMock = new Mock<ISecurityService>();
userName = "testUser";
password = "123";
userBuilder = new UserBuilder(userName, password, person, securityServiceMock.Object);
user = new User(userName, password, person, securityServiceMock.Object);
}
这是我想为ISecurityService 创建模拟的地方。我将未散列的密码传递给User 类的构造函数。
我的期望是,当创建新用户时,我已经对属于他的密码进行了哈希处理。
但是当我使用调试器查看创建时发生了什么:
Salt = securityService.GenerateSalt(4);
我明白了:
{byte[0]}
密码:
Password = securityService.GenerateHashedAndSaltedPassword(password, Salt);
我得到空值。调试器从不点击此方法。
任何人都知道我在这里做错了什么。创建模拟时是否传递了错误的值,或者我期望得到新对象初始化时无法得到的东西?
【问题讨论】:
-
你已经为接口创建了模拟,如果你希望它的方法返回你需要设置它们的东西。您不应该期望 mock 会从您的一个类中获取实现,因为您正在模拟接口而不是类。似乎在您的场景中您不需要模拟此接口,而是传递
SecurityService类的真实实例 -
@SergeyS 感谢您的回复。我试过传递 SecurityService 类的真实实例,但结果是一样的:(
-
this
var securityServiceMock = new Mock<ISecurityService>();只创建空的模拟,其中方法什么都不做。如果你想设置你的模拟,你可以这样做securityServiceMock.Setup(m => m.GenerateSalt(It.IsAny<int>())).Returns(new byte[] {1, 2, 3}); -
@tym32167 你可能想把它作为答案,这也是我所说的需要做的事情。
-
@nemo_87 取决于您和您的代码。如果您打算在多个测试中重用这个模拟对象,它应该在 Init 中,如果您只在本地使用它 - 在您的测试中。
标签: c# unit-testing moq