繁体   English   中英

在 C# 中使用 Moq 的 Mock 接口实现

[英]Mock interface implementation using Moq in C#

我正在尝试使用 Moq 编写 Xamarin.Forms UI 测试来模拟我的身份验证界面:[上一个问题][1]。 我重构了我的应用程序,以便我的SignIn(string username, string password)方法位于实现 IAuthService 的IAuthService 我现在遇到了 mocking IAuthService的问题,基本上“替换”了单击Sign In按钮时发生的实际登录验证。 在我的CloudAuthService class (实现IAuthService )中,我正在对 Amazon Cognito 进行身份验证,但我想在 UI 测试中模拟此结果,因此它不会调用云服务。

编辑:经过很多建议,我决定将我当前的实现包括在下面。 尽管来自Console.WriteLine(App.AuthApi.IsMockService()); BeforeEachTest()方法中结果为true (如预期的那样)。 但是,在App()构造函数方法中运行相同的东西会导致false 所以在应用程序实际启动之前它似乎没有运行,有没有办法让 UITest 代码在应用程序初始化之前运行?

登录页面

[XamlCompilation(XamlCompilationOptions.Compile)]
public sealed partial class LoginPage
{
    private readonly IBiometricAuthentication _bioInterface;

    private static readonly Lazy<LoginPage>
        Lazy =
            new Lazy<LoginPage>
                (() => new LoginPage(App.AuthApi));

    public static LoginPage Instance => Lazy.Value;

    private string _username;

    private string _password;

    private LoginPageViewModel _viewModel;

    private IAuthService _authService;

    public LoginPage(IAuthService authService)
    {
        InitializeComponent();
        _authService = authService;

        _viewModel = new LoginPageViewModel();

        BindingContext = _viewModel;
    }

    private void LoginButtonClicked(object sender, EventArgs args)
    {
          _username = UsernameEntry.Text;
          _password = PasswordEntry.Text;
          LoginToApplication();
    }

    public async void LoginToApplication()
    {
          AuthenticationContext context = await _authService.SignIn(_username, _password);
    }
}

应用程序 Class

public partial class App
{
    public static IAuthService AuthApi { get; set; } = new AWSCognito()
    public App()
    {
        Console.WriteLine(AuthApi.IsMockService())
        // AuthApi = new AWSCognito(); // AWSCognito implements IAuthService
        InitializeComponent();
        MainPage = new NavigationPage(new LoginPage(AuthApi));
    }
}

测试 Class

class LoginPageTest
{
    IApp app;
    readonly Platform platform;

    public LoginPageTest(Platform platform)
    {
        this.platform = platform;
    }

    [SetUp]
    public void BeforeEachTest()
    {

        var mocker = new Mock<IAuthService>();

        var response = new AuthenticationContext(CognitoResult.Ok)
        {
            IdToken = "SUCCESS_TOKEN"
        };
        mocker.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(() => new MockAuthService().SignIn("a", "a"));
        mocker.Setup(x => x.IsMockService()).Returns(() => new MockAuthService().IsMockService());
        App.AuthApi = mocker.Object;
        Console.WriteLine(App.AuthApi.IsMockService());

        app = AppInitializer.StartApp(platform);
    }


    [Test]
    public void ClickingLoginWithUsernameAndPasswordStartsLoading()
    {
        app.WaitForElement(c => c.Marked("Welcome"));
        app.EnterText(c => c.Marked("Username"), new string('a', 1));
        app.EnterText(c => c.Marked("Password"), new string('a', 1));

        app.Tap("Login");

        bool state = app.Query(c => c.Class("ProgressBar")).FirstOrDefault().Enabled;

        Assert.IsTrue(state);
    }
}

您的问题似乎是您在完成测试注入了模拟。 这意味着它在执行时使用原始的 AuthService。 如果我们在执行任何操作之前重新排列代码以移动注入,我们应该会看到我们期望的结果:

    // let's bring this mock injection up here

    var mocker = new Mock<IAuthService>();

    mocker.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(response)).Verifiable();
    App.AuthApi = mocker.Object;

    // now we try to login, which should call the mock methods of the auth service
    app.WaitForElement(c => c.Marked("Welcome to Manuly!"));
    app.EnterText(c => c.Marked("Username"), new string('a', 1));
    app.EnterText(c => c.Marked("Password"), new string('a', 1));

    app.Tap("Login");
    var response = new AuthenticationContext(CognitoResult.Ok)
    {
        IdToken = "SUCCESS_TOKEN",

    };


    bool state = app.Query(c => c.Class("ProgressBar")).FirstOrDefault().Enabled;

    Assert.IsTrue(state);

现在尝试执行它,它应该按照您的意愿执行。

编辑:正如 Nkosi 在评论中指出的那样,在构造函数中设置了 static Auth 服务来防止这种情况发生。

所以这也需要改变:

public partial class App
{
    public static IAuthService AuthApi { get; set; } =new AWSCognito(); // assign it here statically
    public App()
    {
            // AuthApi = new AWSCognito(); <-- remove this
        InitializeComponent();
        MainPage = new NavigationPage(new LoginPage(AuthApi));
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM