2016-09-13 5 views
0

Я раньше не использовал Moq для насмешливого контекста, и я был уверен, что это простая работа, так как у меня есть некоторый опыт работы с RhinoMock. Но когда я пытаюсь сделать что-то просто, чтобы использовать UnitTest, чтобы проверить, правильно ли создан объект, я не получаю ожидаемых результатов.Получение значений возвращаемого значения из методов при использовании Moq

Допустим, у меня есть пользовательский объект, в котором есть некоторые данные. Это User class:

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

В моих тестах Unit У меня есть 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); 
} 

Здесь я хочу создать moc k для ISecurityService. Я передаю пароль, который не хешируется конструктору класса User. Мое предположение заключается в том, что при создании нового пользователя у меня есть хешированный пароль, который принадлежит ему.

Но когда я использую отладчик, чтобы посмотреть, что происходит на создание для:

Salt = securityService.GenerateSalt(4); 

я получаю:

{byte[0]} 

И пароль:

Password = securityService.GenerateHashedAndSaltedPassword(password, Salt); 

я получаю нулевое значение , Отладчик никогда не использует эти методы.

У кого-нибудь есть представление, что я делаю неправильно здесь. Я передаю неправильное значение при создании макета или я ожидаю получить то, что я не могу получить при инициализации нового объекта?

+0

Вы создали mock для интерфейса, если вы хотите, чтобы его методы возвращали то, что вам нужно для их настройки. Вы не должны ожидать, что макет возьмет реализацию от одного из ваших классов, поскольку вы издеваетесь над интерфейсом, а не с классом. Похоже, что в вашем сценарии вам не нужно издеваться над этим интерфейсом, а вместо этого передавать реальный экземпляр класса «SecurityService» – SergeyS

+0

@SergeyS Спасибо, что ответили. Я попытался передать реальный экземпляр класса SecurityService, но результат был тот же :( –

+1

this '' 'var securityServiceMock = new Mock ();' '' создает только пустые макеты, где методы ничего не делают. настройте свой макет, вы можете сделать это таким образом '' 'securityServiceMock.Setup (m => m.GenerateSalt (It.IsAny ())). Возвращает (новый байт [] {1, 2, 3});' '' – tym32167

ответ

1

Это потому, что вы используете MockBehavior.Loose (это значение по умолчанию), когда вы создаете экземпляр объекта Mock().

При замене экземпляра в вашем [Init] Способ по:

var securityServiceMock = new Mock<ISecurityService>(MockBehavior.Strict); 

Он не будет возвращать значение по умолчанию, а бросит MockException. Это заставит вас настроить любой вызов вашего макетного объекта, чтобы явно определить поведение вашего макета.

Я знаю, что между Loose vs Strick ведется религиозная война, поэтому вы можете выбрать свой лагерь, но в любом случае вам нужно определить, какое поведение следует принимать, когда вызывается данный издеваемый метод.

Для этого необходимо вызвать метод Setup() и передать lambda, который определит, какой метод должен быть настроен и с какими аргументами (вы можете использовать статический класс It.Is/IsAny имеет предикаты вместо определенных значений). Затем вам нужно вызвать Return() на полученный объект, чтобы определить, что метод должен возвращать при вызове (вы можете использовать свободно обозначение)

, который даст вам что-то вдоль линий:

var myMockedResult = //... whatever 
var securityServiceMock = new Mock<ISecurityService>(MockBehavior.Strict); 
securityServiceMock 
    .Setup(s => s.GenerateHashedAndSaltedPassword(It.IsAny<string>(), It.IsAny<byte[]>)) 
    .Returns(myMockedResult);