我有一个视图,我想嘲笑Show
行为。
输入凭据后,[Connecter]按钮自动启用,然后用户可以单击。我希望我可以重现这种行为,而不必显示视图,实际上真的输入我的凭据。
该应用程序是IApplicationPresenter
提供的WinForms MDI。 IApplicationPresenter
会引发ShowView
订阅的IApplicationView
。
然后,当IApplicationView.Shown
时,IApplicationPresenter
强制用户进行身份验证,如下所示:
IApplicationPresenter.OnViewShown
public void OnViewShown() { forceAuthentication(); }
private void forceAuthentication() {
IAuthenticationView authView = new AuthenticationView();
IAuthenticationPrenseter authPresenter = new AuthenticationPresenter();
authPresenter.ShowView();
}
就像我闻到一样。
IAuthenticationView
注入IApplicationPresenter
。然后,这将允许我向其注入我的模拟视图,并避免实际显示视图,这实际上是我想要的。它是制作它的最好方法吗?现在,我想测试一下,当显示IApplicationView
时,会通知IApplicationPresenter
并强制进行身份验证。
在这里嘲笑方面有什么更好的方法?
更新
IVIEW
public interface IView {
void CloseView();
void SetTitle(string title);
void ShowView();
void RaiseVoidEvent(VoidEventHandler @event);
event VoidEventHandler OnViewInitialize;
event VoidEventHandler OnViewShown;
}
IApplicationView
public interface IApplicationView : IView {
void OnUserAuthenticated();
event VoidEventHandler ManageRequestsClicked;
}
IPresenter
public interface IPresenter<V> where V : IView {
V View { get; }
IDatabaseUser CurrentUser { get; }
void CloseView();
void OnViewInitialize();
void RaiseVoidEvent(VoidEventHandler @event);
void ShowView();
event VoidEventHandler OnCloseView;
event VoidEventHandler OnShowView;
}
演示
public abstract class Presenter<V> : IPresenter<V> where V : IView {
public Presenter(V view) {
if (view == null) throw new ArgumentNullException("view");
View = view;
View.OnViewInitialize += OnViewInitialize;
OnCloseView += View.CloseView;
OnShowView += View.ShowView;
}
public virtual IDatabaseUser CurrentUser { get; protected set; }
public virtual V View { get; private set; }
public virtual void CloseView() { RaiseVoidEvent(OnCloseView); }
public virtual void OnViewInitialize() { }
public void RaiseVoidEvent(VoidEventHandler @event) { if (@event != null) @event(); }
public virtual void ShowView() { RaiseVoidEvent(OnShowView); }
public virtual event VoidEventHandler OnCloseView;
public virtual event VoidEventHandler OnShowView;
}
IApplicationPresenter
public interface IApplicationPresenter : IPresenter<IApplicationView> {
IAuthenticationPresenter AuthenticationPresenter { get; set; }
void OnManageRequestsClicked();
void OnUserAuthenticated(UserAuthenticatedEventArgs e);
void OnViewShown();
}
ApplicationPresenter
public class ApplicationPresenter : Presenter<IApplicationView>, IApplicationPresenter {
public ApplicationPresenter(IApplicationView view) : this(view, null) { }
public ApplicationPresenter(IApplicationView view, IAuthenticationPresenter authPresenter) : base(view) {
AuthenticationPresenter = authPresenter;
View.OnViewShown += OnViewShown;
View.ManageRequestsClicked += OnManageRequestsClicked;
}
public IAuthenticationPresenter AuthenticationPresenter { get { return authenticationPresenter; } set { setAuthenticationPresenter(value); } }
public void OnManageRequestsClicked() {
var requests = new GestionDemandeAccesInformationForm();
requests.Database = database;
requests.MdiParent = (System.Windows.Forms.Form)View;
requests.Show();
}
public void OnUserAuthenticated(UserAuthenticatedEventArgs e) {
CurrentUser = new DatabaseUser(e.Login, e.Password, e.DatabaseInstance);
database = new DatabaseSessionFactory(CurrentUser);
setAppTitle();
showRequestsManagementView();
}
public void OnViewShown() { forceAuthentication(); }
}
IAuthenticationView
public interface IAuthenticationView : IView {
string ErrorMessage { get; set; }
string Instance { get; set; }
IEnumerable<string> Instances { get; set; }
string Login { get; set; }
string Password { get; set; }
void EnableConnectButton(bool enabled);
void SetDefaultInstance(string defaultInstance);
void RaiseSelectionChangedEvent(SelectionChangedEventHandler @event, SelectionChangedEventArgs e);
event VoidEventHandler OnConnect;
event SelectionChangedEventHandler OnDatabaseInstanceChanged;
event VoidEventHandler OnLoginChanged;
event VoidEventHandler OnPasswordChanged;
}
IAuthenticationPresenter
public interface IAuthenticationPresenter : IValidatablePresenter, IPresenter<IAuthenticationView> {
void OnConnect();
void OnViewDatabaseInstanceChanged(SelectionChangedEventArgs e);
void OnViewLoginChanged();
void OnViewPasswordChanged();
void RaiseUserAuthenticatedEvent(UserAuthenticatedEventArgs e);
event UserAuthenticatedEventHandler UserAuthenticated;
}
AuthenticationPresenter
public class AuthenticationPresenter : Presenter<IAuthenticationView>, IAuthenticationPresenter {
public AuthenticationPresenter(IAuthenticationView view, IMembershipService service) : base(view) {
MembershipService = service;
View.ErrorMessage = null;
View.SetTitle(ViewTitle);
subscribeToEvents();
}
public bool IsValid { get { return credentialsEntered(); } }
public IMembershipService MembershipService { get; set; }
public virtual void OnConnect() {
if (noDatabaseInstanceSelected()) display(MissingInstanceErrorMessage);
else if (noLoginEntered()) display(MissingLoginErrorMessage);
else if (noPasswordEntered()) display(MissingPasswordErrorMessage);
else {
display(EverythingIsFine);
if (isAuthenticUser()) notifyTheApplicationThatTheUserIsAuthentic();
else { display(InvalidLoginOrPasswordErrorMessage); }
}
}
public override void OnViewInitialize() {
base.OnViewInitialize();
View.ErrorMessage = null;
View.Instances = Configuration.DatabaseInstances;
View.SetDefaultInstance(Configuration.DefaultInstance);
}
public void OnViewDatabaseInstanceChanged(SelectionChangedEventArgs e) { View.Instance = (string)e.Selected; }
public void OnViewLoginChanged() { View.EnableConnectButton(IsValid); }
public void OnViewPasswordChanged() { View.EnableConnectButton(IsValid); }
public void RaiseUserAuthenticatedEvent(UserAuthenticatedEventArgs e) { if (UserAuthenticated != null) UserAuthenticated(e); }
public event UserAuthenticatedEventHandler UserAuthenticated;
}
答案 0 :(得分:2)
如果我是你,我会注入一个工厂来创建AuthenticationPresenter
,在你的测试中我会打电话给OnViewShown()
并在你的模拟器(工厂退回的演示者)上验证ShowView
被称为。{/ p>
修改强> 请注意,我还没有编译这个,我现在没有C#编译器。
这是我的测试版本。基于我对你真正想要测试的内容的解释:
[TestClass]
public class ApplicationPresenterTests
{
[TestClass]
public class OnViewShown : ApplicationPresenterTests
{
[TestMethod]
public void ForceAuthentication()
{
// given
var authenticationPresenterFactory = new Mock<IAuthenticationPresenterFactory>();
var authenticationPresenter = new Mock<IAuthenticationPresenter>();
authenticationPresenterFactory.Setup(f => f.create()).Returns(authenticationPresenter.Object);
var presenter = new ApplicationPresenter(authenticationPresenterFactory);
// when
presenter.OnViewShown();
// then
authenticationPresenter.Verify(p => p.ShowView());
}
}
答案 1 :(得分:0)
到目前为止,我已经提出了完美无瑕的解决方案。
所有关于设置模拟对象按预期工作的方法。
[TestClass]
public abstract class ApplicationPresenterTests {
[TestClass]
public class OnViewShown : ApplicationPresenterTests {
[TestMethod]
public void ForceAuthentication() {
// arrange
// act
Presenter.OnViewShown();
var actual = Presenter.CurrentUser;
// assert
Assert.IsNotNull(actual);
Assert.IsInstanceOfType(actual, typeof(IDatabaseUser));
}
}
[TestInitialize]
public void ApplicationMainPresenterSetUp() {
Mock<IAuthenticationView> authView = new Mock<IAuthenticationView>(MockBehavior.Strict);
authView.SetupProperty(v => v.ErrorMessage);
authView.SetupGet(v => v.Instance).Returns(RandomValues.RandomString());
authView.SetupGet(v => v.Login).Returns(RandomValues.RandomString());
authView.SetupGet(v => v.Password).Returns(RandomValues.RandomString());
authView.Setup(v => v.CloseView());
authView.Setup(v => v.SetTitle(It.IsAny<string>()));
authView.Setup(v => v.ShowView()).Raises(v => v.OnConnect += null).Verifiable();
Mock<IMembershipService> authService = new Mock<IMembershipService>(MockBehavior.Loose);
authService.Setup(s => s.AuthenticateUser(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(true);
IAuthenticationPresenter authPresenter = new AuthenticationPresenter(authView.Object, authService.Object);
ApplicationView = new ApplicationForm();
Presenter = new ApplicationPresenter(ApplicationView, authPresenter);
}
protected IApplicationView ApplicationView { get; private set; }
protected IApplicationPresenter Presenter { get; private set; }
}
因此,关键的变化是将IAuthenticationPresenter
的依赖性注入IApplicationPresenter
,因此ApplicationPresenter
构造函数重载。
虽然这已经解决了我的问题,但我更好地理解了PresenterFactory
注入ApplicationPresenter
的必要性,因为这是处理应用程序中所有内容的演示者,即调用每个有自己的演示者的其他视图。
在我之前,面临更复杂的挑战。请继续关注!