2009-06-04 11 views
5

Soy nuevo en TDD y tengo problemas con una de mis pruebas unitarias. Parece que no puedo entender qué hacer a continuación. . :(Estoy tratando de probar la unidad un servicio de mina llamada AccountService y estoy probando un método llamado DoLogin (nombre de usuario, contraseña) Esto es un código de ejemplo:Unidad Comprobación de un inicio de sesión en ASP.NET

[Test] 
    public void User_With_Correct_Username_And_Pass_Should_Login_Successfully() 
    { 
     // Arrange 
     var accountService = new AccountService(); 

     // Act 
     bool result = accountService.DoLogin("test", "test"); 

     // Assert 
     Assert.IsTrue(result); 
    } 

    public class AccountService : IAccountService 
    { 
     public bool DoLogin(string username, string password) 
     { 
     if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) 
      return false; 

     return true; 
     } 
    } 

lo que esta prueba pasados, pero ahora lo hacen Sí, ¿cómo realmente pruebo si se produjo un inicio de sesión válido? ¿Debo implementar una prueba de integración y probar el inicio de sesión con un DB real o en memoria? Lo siento si estoy haciendo cosas totalmente incorrectas. Realmente espero que uno día para obtener este material TDD abajo. Gracias

Respuesta

14

Su experiencia es muy similar a la mía está comenzando. Mientras me venden en TDD y no haría las cosas de manera diferente, ciertamente entiendo tu confusión. Es importante recordar que TDD es una filosofía de diseño. Dicho eso, creo que puedo ayudar a aclarar algunas de tus frustraciones.

  1. Comience pensando en lo que está tratando de lograr, no en un nivel de prueba individual, pero qué es lo que está tratando de hacer. Si su tarea (historia del usuario) implica tomar algunas credenciales e intentar autenticar al usuario actual en función de esas credenciales, entonces comience desde allí y siga su camino hacia abajo. Usted parece estar yendo en esta dirección, solamente se queda pegada sobre los próximos pasos

  2. Cuando se trabaja en una prueba individual, pensar en ella en términos de expected behavior en lugar de sólo la verificación de algunas entradas y salidas. Piense en sí mismo como si usara este componente, y simplemente escriba una línea de código de la forma en que desea que se escriba. Deje que esta parte ayude a conducir la interfaz/contrato de su servicio. Tienes que hacerte la pregunta: "Si tuviera que llamar a este método, ¿cómo iba a saber si funcionaba? ¿Qué esperaría que hiciera?" Esto determinará qué tipo de afirmaciones debe hacer.

  3. Determine cuáles son sus dependencias externas, y utilize abstractions instead (principio de inversión de dependencia). Si estas dependencias son algo que le interese como parte de su verificación de comportamiento, entonces use dependency injection para poder usar un mock en su prueba.

  4. Siempre, siempre, siempre siga este orden [Escriba su prueba, mire si falla, código para pasar, refactorizador]. ¡¡¡APRENDA DE MIS ERRORES !!! Créanme, esto no es negociable. De lo contrario, es probable que culpe a sus problemas con TDD cuando no se está empleando correctamente.

Ok, por lo que poner todo esto junto con su ejemplo, y algunos muy bien proporcionado test cases from lance, podríamos hacer algo como esto:

[Test] 
public void ShouldAuthenticateValidUser() 
{ 
    IMyMockDa mockDa = new MockDataAccess(); 
    var service = new AuthenticationService(mockDa); 

    mockDa.AddUser("Name", "Password"); 

    Assert.IsTrue(service.DoLogin("Name", "Password")); 

    //Ensure data access layer was used 
    Assert.IsTrue(mockDa.GetUserFromDBWasCalled); 
} 

[Test] 
public void ShouldNotAuthenticateUserWithInvalidPassword() 
{ 
    IMyMockDa mockDa = new MockDataAccess(); 
    var service = new AuthenticationService(mockDa); 

    mockDa.AddUser("Name", "Password"); 

    Assert.IsFalse(service.DoLogin("Name", "BadPassword")); 

    //Ensure data access layer was used 
    Assert.IsTrue(mockDa.GetUserFromDBWasCalled); 
} 

Ok, así que hay mucho que hacer allí, y quizás mucho para investigar. Sin embargo, puede comenzar a ver cómo es posible realizar pruebas exhaustivas utilizando un mejor diseño. En los ejemplos anteriores, es importante tener en cuenta que el objeto simulado se rueda de forma personalizada, pero no tiene que pasar por todo este dolor. Hay muchos Frameworks burlones por ahí. Por ejemplo, utilizando RhinoMocks, la prueba se vería así:

[Test] 
public void ShouldAuthenticateValidUser() 
{ 
    var mockRepo = new MockRepository(); 
    var mockDa = mockRepo.DynamicMock<IMyMockDa>(); 

    var service = new AuthenticationService(mockDa); 

    using(mockRepo.Record()) 
    { 
     //I realize this is a terrible method and should not exist if you 
     // care about security, but for demonstration purposes... 
     Expect.Call(mockDa.GetPassword("User")).Return("Password"); 
    } 
    using(mockRepo.Playback()) 
    { 
     Assert.IsTrue(service.DoLogin("User", "Password")); 
    } 
} 

acostumbrarse a hacer las cosas de manera manual del primero para que entienda los conceptos, y luego pasar a la utilización de un marco. ¡Uf! Mucha información, pero como puede ver, TDD es una filosofía de diseño completa. Sin embargo, dará como resultado un código más limpio, un mejor diseño y menos errores.

+1

¡Muchas gracias por tomarse el tiempo de escribir esto! Realmente lo aprecio. Dijiste muchas cosas buenas y probablemente me tome un tiempo entender todo. Tienes razón en que tengo que acostumbrarme a pensar de manera diferente cuando hago TDD. Espero que mi confusión pase algún día, pero eso solo llevará tiempo. ¡Gracias de nuevo! – CalebHC

+0

Pasó mucho tiempo antes de que tuviera ese momento "Ah Ha", pero ahora estoy totalmente convertido. Te animo a que compruebes otra publicación SO que hice sobre TDD: http://stackoverflow.com/questions/106800/unit-testing-guidelines/106813#106813 – Josh

+1

La representación incompleta que viste es un error conocido con respuestas antiguas - Puedes arreglar esto para cualquier respuesta (no solo la tuya) enviando cualquier edición, lo que obliga a volver a generar la respuesta. Esto también explica por qué se ve bien cuando aparece por primera vez el editor. He retocado el formato aquí, pero también puedes enviar una edición de stub y deshacerlo y aún obligará a la respuesta a volver a generar. – BoltClock

0

Usted debe tener una prueba de que un nombre de usuario válido o contraseña no válida provoca DoLogin() falle.

dado el nombre de la función, (DoLogin() en lugar de CheckLogin()), creo que la función también debería tener algún efecto secundario. La prueba debería verificar ese efecto secundario. Realmente es necesario aclarar qué es eso antes de que alguien pueda aclarar cómo se debe verificar.

1

Pase lo que sabe que son credenciales válidas y no válidas a DoLogin, y luego compare los resultados con lo que espera. Trate de imaginar todas las combinaciones/entradas posibles (leídas: razonables) de los parámetros de "nombre de usuario" y "contraseña" que el usuario proporcionará, y cree una prueba para cada uno.

Si su lógica de negocio DoLogin es creíble, estamos definiendo un nombre de usuario "válido" (y una contraseña "válida") para que sea cualquier cosa que se rellene. Muy bien, por el bien de la discusión.

Algunas pruebas sencillas vienen a la mente:

Login_With_Null_UserName_Fails() 
Login_With_Populated_UserName_Succeeds() 
Login_With_Empty_UserName_Fails() 
Login_With_Null_Password_Fails() 
Login_With_Populated_Password_Succeeds() 
Login_With_Empty_Password_Fails() 

O, consideran combinaciones:

Login_With_Null_UserName_And_Populated_Password_Fails() 
Login_With_Populated_UserName_And_Populated_Password_Succeeds() 
Login_With_Empty_UserName_And_Null_Password_Fails() 
etc 
etc 
+0

Cool, gracias. Entonces, cuando termine de agotar mi lista de pruebas para DoLogin, ¿cuál es mi siguiente paso? ¿Realmente pruebo el inicio de sesión contra un DB? – CalebHC

+0

Si cree que existe un riesgo suficiente en sus parámetros de envío y en obtener los resultados correctos de sus procedimientos almacenados, ¡seguro! Las pruebas ayudan a reducir el riesgo y mejorar el código. Recomiendo pruebas en cualquier lugar donde razonablemente anticipe alguna oportunidad. – lance

Cuestiones relacionadas