I am trying to declare and mock a local interface that interacts with a cloud authentication API. My local class implements this interface and provides the functionality to interact with the cloud API. To be able to run UI tests on this application, I would like to be able to implement a 'Mock' interface and inject this into the application to be used in place of the functioning class. I am currently using the Moq library.
My LoginPage
currently is initialized and displayed within the App()
constructor method as a navigation page. I would like to be able to either set the instance of the AuthApi
as the 'MockedAPI' within my test, or inject the mock into the LoginPage
directly for use. I was hoping that this 'MockedAPI' would be able to override this App.AuthApi
before the application started, but it doesn't seem to be the case here.
App.xaml.cs
public partial class App { public static IAuthService AuthApi { get; set; } = new AWSCognito(); // AWSCognito implements IAuthService public App() { InitializeComponent(); MainPage = new NavigationPage(new LoginPage()); } }
LoginPageTest.cs
[SetUp] public void BeforeEachTest() { var mocker = new Mock<IAuthService>(); mocker.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(() => new MockAuthService().SignIn("a", "a")); App.AuthApi = mocker.Object; AppManager.StartApp(); app = AppInitializer.StartApp(platform); } [Test] public void EnterUsernameAndPassword() { 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); }
MockAuthService
public class MockAuthService : IAuthService { public Task<AuthenticationContext> SignIn(string username, string password) { return Task.FromResult(new AuthenticationContext(CognitoResult.Ok) { IdToken = "SUCCESS_TOKEN", }); } }
LoginPage.cs
XamlCompilation(XamlCompilationOptions.Compile)] public sealed partial class LoginPage { private string _username; private string _password; private LoginPageViewModel _viewModel; public LoginPage() { InitializeComponent(); _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 App.AuthApi.SignIn(_username, _password); } }