2017-01-27 2 views
2

У меня есть этот метод внутри контроллера:C# MVC Мок модель через интерфейс контроллер файлов нарушает

[HttpPatch] 
[AllowAdminOnly] 
public JsonResult EditUser(User _user) 
{ 
    try 
    { 
     if (ModelState.IsValid) 
     { 
      _user.Edit(); 
     } 
     else 
     { 
      string error_messages = ""; 
      foreach (var e in ModelState.Select(x => x.Value.Errors).Where(y => y.Count > 0).ToList()) 
      { 
       error_messages += e[0].ErrorMessage + "\n"; 
      } 
      throw new Exception(error_messages); 
     } 
     return MessageHelper(@Resources.Global.success, @Resources.Users.success_editing_user, "success"); 
    } 
    catch (Exception err) 
    { 
     return ErrorHelper(@Resources.Global.error, @Resources.Users.error_editing_user, err.Message); 
    } 
} 

Для модульного тестирования этого метода, я нашел ссылки (...) говорили, что я должен " макет "_user.Edit();. Кажется, это хорошо, это позволит избежать сохранения данных в базе данных и ускорит тесты.

Мой тест затем (для действительного пользователя) становится:

[TestMethod] 
public void UserController_EditUser_Valid() 
{ 
    // Arrange 
    FundController controller = new UserController(); 
    controller.ControllerContext = TestModelHelper.AdminControllerContext(); 

    var _user = new Mock<Fund>(); 
    _user.SetupGet(f => f.id).Returns(1); 
    _user.SetupGet(f => f.name).Returns("User name"); 
    _user.SetupGet(f => f.nickname).Returns("User nickname"); 
    _user.SetupGet(f => f.active).Returns(true); 
    _user.Setup(f => f.Edit()).Callback(() => {}).Verifiable(); 

    // Act 
    var result = (JsonResult)controller.EditUser(_user.Object); 
    SimpleMessage resultMessage = m_serializer.Deserialize<SimpleMessage>(m_serializer.Serialize(result.Data)); 

    // Assert 
    Assert.IsNotNull(resultMessage, "Result must not be null"); 
    Assert.IsTrue(resultMessage.status.Equals("success"), "status must be 'success'"); 
} 

Но когда я это делаю, я получаю следующее сообщение об ошибке:

Test Name: UserController_EditUser_Valid 
Test FullName: Pmanager.Tests.Controllers.UserControllerTest.UserController_EditUser_Valid 
Test Source: ...\Pmanager\Pmanager.Tests\Controllers\UserControllerTest.cs : line 95 
Test Outcome: Failed 
Test Duration: 0:00:00,0179908 

Result StackTrace: 
em Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo method) 
    em Moq.Mock.<>c__DisplayClass66_0`2.<SetupGet>b__0() 
    em Moq.PexProtector.Invoke[T](Func`1 function) 
    em Moq.Mock.SetupGet[T,TProperty](Mock`1 mock, Expression`1 expression, Condition condition) 
    em Moq.Mock`1.SetupGet[TProperty](Expression`1 expression) 
    em Pmanager.Tests.Controllers.UserControllerTest.UserController_EditUser_Valid() na ...\Pmanager\Pmanager.Tests\Controllers\UserControllerTest.cs:linha 100 
Result Message: 
Test method Pmanager.Tests.Controllers.UserControllerTest.UserController_EditUser_Valid threw exception: 
System.NotSupportedException: Valid setup on a non-virtual (overridable in VB) member: f => f.id 

Я нашел документацию (...), говоря, что я должен использовать интерфейс вместо класса при создании «mock».

Итак, я создал интерфейс:

public interface IUser 
{ 
    int id { get; set; } 
    string name { get; set; } 
    string nickname { get; set; } 
    bool active { get; set; } 
    void Edit(); 
} 

, а затем я изменил все для IUser, контроллера метод подписи:

public JsonResult EditUser(IUser _user); 

тест "фиктивный" декларация:

var _user = new Mock<IUser>(); 

и так далее.

Теперь тест работает, но метод фактического контроллера для редактирования пользователя не работает!

Как я могу собрать все эти вещи, не нарушая функциональность контроллера trully?

+1

'вар _user = новый Mock ()' или 'вар _user = новый Mock ();' – Shyju

+0

'вар _user = новый Mock ();', извините –

+0

вы передаете макет реализации от IUser. так что вам также нужно обеспечить макетную реализацию Edit! Ваше существующее Редактирование не будет работать. Вы ожидали этого? – Shyju

ответ

1

Обновление с ontroller использовать зависимость для обновления модели пользователя. Удалите эту функциональность из самой модели. Модели должны быть POCOs/DTO.

public class UserController : Controller { 
    readonly IUserService userService; 

    public UserController(IUSerService userService) { 
     this.userService = userService; 
    } 

    [HttpPatch] 
    [AllowAdminOnly] 
    public JsonResult EditUser(User _user) { 
     try { 
      if (ModelState.IsValid) { 
       userService.Edit(user); 
      } else { 
       string error_messages = ""; 
       foreach (var e in ModelState.Select(x => x.Value.Errors).Where(y => y.Count > 0).ToList()) { 
        error_messages += e[0].ErrorMessage + "\n"; 
       } 
       throw new Exception(error_messages); 
      } 
      return MessageHelper(@Resources.Global.success, @Resources.Users.success_editing_user, "success"); 
     } catch (Exception err) { 
      return ErrorHelper(@Resources.Global.error, @Resources.Users.error_editing_user, err.Message); 
     } 
    } 
} 

IUserService, где что-то вроде

public interface IUserService { 
    void Edit(User user); 
} 

и ее осуществление производства будет выполнять нужное действие. Не забудьте зарегистрировать абстракцию и реализацию с помощью того, что вы используете.

Тест затем издевается над зависимостями, необходимыми для его автономной работы.

[TestMethod] 
public void UserController_EditUser_Should_Be_Valid() { 
    // Arrange  
    var _user = new User { 
     id = 1, 
     name = "User name", 
     nickname = "User nickname", 
     active = true 
    }; 

    var mockService = new Mock<IUserService>(); 
    mockService .Setup(m => m.Edit(_user)).Verifiable(); 

    var controller = new UserController(mockService.Object); 
    controller.ControllerContext = TestModelHelper.AdminControllerContext(); 

    // Act 
    var result = controller.EditUser(_user) as JsonResult; 

    // Assert 
    Assert.IsNotNull(result, "Result must not be null");   
    mockService.Verify(); // verify that the service was call successfully. 
} 
+0

вправо, я дам ему попробовать –

+0

Я тебя достал, это сработало. Кроме того, спасибо за термин POCOs/DTOs, я не знал об этом. Более того, я не знал, что должен сделать mockService.Verify(); int и. огромное спасибо –

0

Ну, я все еще сомневаюсь в правильном способе делать все это.

Но я понял, как сделать работу. Это:

  • держать подпись метода контроллера, как это должно быть: public JsonResult EditUser(User _user);
  • сделать синтаксический разбор в издеваться при прохождении его метода контроллера: var result = (JsonResult)controller.EditUser(_user.Object as User);

Хотя это работает, я не уверены в том, весь материал находится в гармонии ... :(

Надежда кто-то может дать лучший ответ.

Смежные вопросы