c# - 如何最小起订量这个 View ?

标签 c# winforms unit-testing moq mvp

我有一个 View ,我想模拟它的 Show 行为。

Authentication dialog

输入凭据后,[连接器]按钮将自行启用,然后用户可以单击。我希望我可以重现此行为,而无需显示 View 并实际输入我的凭据。

该应用程序是由 IApplicationPresenter 呈现的 WinForms MDI。 IApplicationPresenter 引发 IApplicationView 订阅的 ShowView

然后,当 IApplicationView.Shown 时,IApplicationPresenter 强制用户进行身份验证,如下所示:

IApplicationPresenter.OnViewShown

public void OnViewShown() { forceAuthentication(); }

private void forceAuthentication() {
    IAuthenticationView authView = new AuthenticationView();
    IAuthenticationPrenseter authPresenter = new AuthenticationPresenter();
    authPresenter.ShowView();
}

就像我能闻到一种东西。

  1. 就像我可以将 IAuthenticationView 注入(inject)到 IApplicationPresenter 中一样。然后,这将允许我将模拟 View 注入(inject)其中,并避免实际显示 View ,这实际上是我想要的。这是最好的制作方法吗?

现在,我想测试一下,当显示 IApplicationView 时,IApplicationPresenter 会收到通知并强制进行身份验证。

在 mock 方面有更好的方法吗?

UPDATE

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

身份验证演示者

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

最佳答案

如果我是你,我会注入(inject)一个用于创建 AuthenticationPresenter 的工厂,并在你的测试中调用 OnViewShown() 并在你的模拟(演示者的)上进行验证由工厂返回)调用 ShowView

编辑 请注意,我还没有编译这个,我现在没有 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());
        }
}

关于c# - 如何最小起订量这个 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22669972/

相关文章:

c# - VS2017 .Net Core 2.0 测试 : "Failed to initialize client proxy: could not connect to test process"

reactjs - 是否可以将 enzyme 测试与 Next js (SSR) 一起使用?

c# - asp.net ashx 请求 404

c# - WPF 如何设置 CollectionViewSource 的最大结果量

c# - MaskedTextBox 多行asciionly

c# - Winforms 静态 HandleCreated 或 OnLoad 事件

c++ - 为什么不能在 Boost.Test 测试用例中创建线程?

c# - 如何在C#中用指针调用C语言编码的dll

c# - 获取 SQL 表的受影响行数

c# - 非UI线程,UI访问