3

Ich versuche, diese Controller-Methode zu testen, die in aktuellen MVC-Projekten standardmäßig zur Verfügung steht.Interfaces zum Mocking von ConfirmEmailAsync und anderen UserManager-Methoden in MVC5

[AllowAnonymous] 
public async Task<ActionResult> ConfirmEmail(string userId, string code) 
{ 
    if (userId == null || code == null) 
    { 
     return View("Error"); 
    } 
    var result = await UserManager.ConfirmEmailAsync(userId, code); 
    return View(result.Succeeded ? "ConfirmEmail" : "Error"); 
} 

Die Accountcontroller hat einen Konstruktor, der eine ApplicationUserManager und einen ApplicationSignInManager als Parameter nehmen, und die passenden Eigenschaften mit eigenem Etter zum Testen zu verwenden. Ich kann jedoch nicht herausfinden, wie die ConfirmEmailAsync-Methode ausgeheckt werden soll.

können Sie verschiedene Schnittstellen im Identity-Namespace verspotten:

var store = new Mock<IUserStore<ApplicationUser>>(); 

store.As<IUserEmailStore<ApplicationUser>>() 
      .Setup(x => x.FindByIdAsync("username1")) 
      .ReturnsAsync((ApplicationUser)null); 

var mockManager = new ApplicationUserManager(store.Object); 

AccountController ac = new AccountController(mockManager, null, GetMockRepository().Object, GetMockLogger().Object); 

Aber ich kann nicht finden oder herauszufinden, welche Schnittstelle ich brauche, um ein Modell von ConfirmEmailAsync zu erstellen.

Wie gehe ich vor? Und als Referenz: Gibt es eine gute Möglichkeit, herauszufinden, an welchen Schnittstellen sich diese Methoden befinden, um sie zu simulieren und zu testen?

+0

ich bin um dies durch Abstrahieren der meisten der Funktionalität der Identität in ein eigenes Projekt, so dass ich Unit-Test einfacher und die Abstraktion in anderen Projekten wiederverwenden kann. Ich begann mit diesem Artikel http://timschreiber.com/2015/01/14/persistence-ignorant-asp-net-identity-with-patterns-part-1/ und dann abgestimmt es für meine Bedürfnisse – Nkosi

Antwort

2

ConfirmEmailAsync ist derzeit nicht Teil einer Schnittstelle im Framework. Es ist in der UserManager<TUser, TKey> Klasse, die die Basisklasse von Identity Framework ist.

Meine Lösung?

Zusammenfassung all die Dinge,

ich um dieses bekam durch die meisten Funktionen der Identität in sein eigenes Projekt zu abstrahieren, so dass ich kann Unit-Test erleichtert und die Abstraktion in anderen Projekten wiederverwenden. Ich habe die Idee nach diesem Artikel

Lesen

Persistence-Ignorant ASP.NET Identity with Patterns

ich dann fein abgestimmt auf die Idee, um meine Bedürfnisse anzupassen. Ich habe im Grunde nur alles, was ich brauchte, von asp.net.identity für meine benutzerdefinierten Schnittstellen ausgetauscht, die mehr oder weniger die Funktionalität des Frameworks widerspiegeln, aber mit dem Vorteil einer einfacheren Mockbarkeit.

IIdentityUser

/// <summary> 
/// Minimal interface for a user with an id of type <seealso cref="System.String"/> 
/// </summary> 
public interface IIdentityUser : IIdentityUser<string> { } 
/// <summary> 
/// Minimal interface for a user 
/// </summary> 
public interface IIdentityUser<TKey> 
    where TKey : System.IEquatable<TKey> { 

    TKey Id { get; set; } 
    string UserName { get; set; } 
    string Email { get; set; } 
    bool EmailConfirmed { get; set; } 
    string EmailConfirmationToken { get; set; } 
    string ResetPasswordToken { get; set; } 
    string PasswordHash { get; set; } 
} 

IIdentityManager

/// <summary> 
/// Exposes user related api which will automatically save changes to the UserStore 
/// </summary> 
public interface IIdentityManager : IIdentityManager<IIdentityUser> { } 
/// <summary> 
/// Exposes user related api which will automatically save changes to the UserStore 
/// </summary> 
public interface IIdentityManager<TUser> : IIdentityManager<TUser, string> 
    where TUser : class, IIdentityUser<string> { } 
/// <summary> 
/// Exposes user related api which will automatically save changes to the UserStore 
/// </summary> 
public interface IIdentityManager<TUser, TKey> : IDisposable 
    where TUser : class, IIdentityUser<TKey> 
    where TKey : System.IEquatable<TKey> { 

    Task<IIdentityResult> AddPasswordAsync(TKey userid, string password); 
    Task<IIdentityResult> ChangePasswordAsync(TKey userid, string currentPassword, string newPassword); 
    Task<IIdentityResult> ConfirmEmailAsync(TKey userId, string token); 
    //...other code removed for brevity 
} 

IIdentityResult

/// <summary> 
/// Represents the minimal result of an identity operation 
/// </summary> 
public interface IIdentityResult : System.Collections.Generic.IEnumerable<string> { 
    bool Succeeded { get; } 
} 

In meiner Default-Implementierung des Identitätsmanager i die ApplicationManager einfach gewickelt und dann abgebildet Ergebnisse und Funktionalität zwischen meinen Typen und die asp.net.identity ty pes.

public class DefaultUserManager : IIdentityManager { 
    private ApplicationUserManager innerManager; 

    public DefaultUserManager() { 
     this.innerManager = ApplicationUserManager.Instance; 
    } 
    //..other code removed for brevity 
    public async Task<IIdentityResult> ConfirmEmailAsync(string userId, string token) { 
     var result = await innerManager.ConfirmEmailAsync(userId, token); 
     return result.AsIIdentityResult(); 
    } 
    //...other code removed for brevity 
} 
0

Haftungsausschluss: Ich arbeite bei Typemock.

Eigentlich benötigen Sie keine Schnittstelle, wenn Sie Typemock verwenden, müssen Sie nur das IdentityResult fälschen und das Verhalten der asynchronen Methode "ConfirmEmailAsync" ändern, zum Beispiel einen Test, der das Szenario eines Unconfirmed überprüft E-Mail:

[TestMethod, Isolated] 
public async Task TestWhenEmailIsBad_ErrorMessageIsShown() 
{ 

    // Arrange 
    // Create the wanted controller for testing and fake IdentityResult 
    var controller = new aspdotNetExample.Controllers.AccountController(); 
    var fakeIdentityRes = Isolate.Fake.Instance<IdentityResult>(); 

    // Fake HttpContext to return a fake ApplicationSignInManager 
    var fakeSIM = Isolate.WhenCalled(() => controller.UserManager).ReturnRecursiveFake(); 

    // Modifying the behavior of ConfirmEmailAsync to return fakeIdentityRes 
    Isolate.WhenCalled(() => fakeSIM.ConfirmEmailAsync("", "")).WillReturn(Task.FromResult<IdentityResult>(fakeIdentityRes)); 
    Isolate.WhenCalled(() => fakeIdentityRes.Succeeded).WillReturn(false); 

    // Act 
    var result = await controller.ConfirmEmail("", "") as ViewResult; 

    // Assert 
    Assert.AreEqual("Error", result.ViewName); 
}