Моя проблема в том, что в моем AdminController я установил _authService.Session
Да, это действительно проблема, так как это ответственность вашей структуры DI, а не кода вашего контроллера. Поэтому, если ISession
не используется непосредственно контроллером, его следует удалить из него. Контроллер не должен выполнять какие-либо операции между службой и какими-либо зависимостями этой службы.
Итак, вот пример:
public class AdminController : Controller
{
private readonly IAuthenticationService _authService;
public AdminController(IAuthenticationService authService)
{
_authService = authService;
}
public ActionResult Register(RegisterModel userInfo)
{
if (!_authService.EmailIsUnique(userInfo.Email))
{
ModelState.AddModelError("Email", Strings.EmailMustBeUnique);
return View(userInfo);
}
return RedirectToAction("Success");
}
}
Обратите внимание, что контроллер администратора не должен полагаться на какой-либо сеанс. Это уже опирается на IAuthenticationService
. Способ реализации этого сервиса не важен. И в этом случае надлежащим модульным тестом будет:
private IAuthenticationService _authService;
private AdminController _controller;
private TestControllerBuilder _builder;
Setup()
{
_authService = MockRepository.GenerateStub<IAuthenticationService>();
_controller = new AdminController(_authService);
_builder = new TestControllerBuilder();
_builder.InitializeController(_controller);
}
[Test]
public void Register_Post_AddModelErrorWhenEmailNotUnique()
{
// arrange
var userInfo = new RegisterModel();
userInfo.Email = "the_email@domain.com";
_authService
.Stub(x => x.EmailIsUnique(userInfo.Email))
.Return(false);
// act
var actual = _controller.Register(userInfo);
// assert
actual
.AssertViewRendered()
.WithViewData<RegisterModel>()
.ShouldEqual(userInfo, "");
Assert.IsFalse(_controller.ModelState.IsValid);
}
UPDATE:
Теперь, когда вы показали свой код, я подтверждаю:
Удалите зависимость ISession из вашего контроллера, поскольку она не нужна, и оставьте это задание платформе DI.
Теперь я вижу, что ваш AuthenticationService сильно зависит от ISession, поэтому внедрение конструктора будет более адаптированным, чем внедрение свойства. Использовать внедрение свойств только для необязательных зависимостей:
public class AuthenticationService : IAuthenticationService
{
private readonly ISession _session;
public AuthenticationService(ISession session)
{
_session = session;
}
public bool EmailIsUnique(string email)
{
var user = _session.Single<User>(u => u.Email == email);
return user == null;
}
}
и последняя оставшаяся часть - это сантехника. Это делается в приложении ASP.NET MVC, которое имеет ссылки на все остальные уровни. И поскольку вы упомянули Ninject, вы можете установить Ninject.MVC3 NuGet и в сгенерированном ~/App_Start/NinjectMVC3
просто настроить ядро:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISession>().To<SessionImpl>();
kernel.Bind<IAuthenticationService>().To<AuthenticationService>();
}