c# bdd mspec

c# - ¿Estoy escribiendo mis primeras especificaciones de MSpec correctamente?



bdd (1)

El contexto se ve bien. Me gusta la forma en que resolviste el conflicto con los alias. Yo diría que el alias Moq puede mejorarse. Considera algo parecido a una oración. Por ejemplo, Param.Is<T> o Value.Is<T> .

Algunas notas, con fragmentos de código, luego toda la especificación reescrita en la parte inferior.

El escenario es tu Subject

El sujeto puede ser el escenario de la historia. Además, se procesa con su informe de ejecución de prueba (especialmente agradable en el informe HTML).

[Subject("Login Page")]

No pierdas el tiempo en "Con" clases base nombradas

El creador de MSpec, Aaron Jensen, ha revertido el uso de la sintaxis "Con" por completo. Los nombres de clase de contexto no se muestran para ningún informe, por lo tanto, evite pasar tiempo inventando un nombre significativo.

public abstract class MembershipContext

The Given es el nombre de su clase de especificación

Nombra la clase de especificación concreta después del Dado en tu historia. Especialmente ya que el nombre de la clase base no se informa en ninguna parte, ¡podría estar perdiendo la mitad de su contexto en el informe! También debe evitar poner el nombre del sistema bajo prueba en nombres de clase de contexto. Esto hace que sus contextos sean más amigables para refactorizar el sistema bajo prueba.

public class When_an_existing_user_enters_valid_credentials

Las clases de especificaciones de base deben contener solo inicialización general

Y a menudo son innecesarios. Conducen a la separación de las fases Organizar y Actuar. Use una clase base para la inicialización de campos comunes, como configurar dependencias simuladas. Pero, no debes simular un comportamiento en una clase base. Y no debe colocar información específica del contexto en la clase base. En su ejemplo, el nombre de usuario / contraseña. De esta manera, puede crear un segundo contexto con credenciales no válidas.

Establish context = () => { membership = new Mock<ISiteMembership>(); loginController = new LoginController(membership.Object); };

Los campos en la clase de especificación de concreto deben ser privados.

Reduce la "ceremonia" del lenguaje en tu examen. Debe colocarlos debajo de todos los delegados específicos de MSpec, ya que esas partes de la especificación cuentan la mayor parte de la historia.

static ActionResult result;

La revisión de especificaciones

La especificación aquí es un excelente ejemplo de cómo establecer un contexto global MembershipContext y heredarlo en un contexto específico para la especificación (por lo tanto, el Establish adicional).

[Subject("Login Page")] public class When_an_existing_user_enters_valid_credentials : MembershipContext { Establish context = () => { membership .Setup<bool>(m => m.Validate( Param.Is<string>(s => s == username), Param.Is<string>(s => s == password))) .Returns(true); }; Because of = () => result = loginController.Login(username, password); It should_log_the_user_in; It should_redirect_the_user_to_the_admin_panel; It should_show_message_confirming_successful_login; static ActionResult result; const string username = "username"; const string password = "password"; } public abstract class MembershipContext { Establish context = () => { membership = new Mock<ISiteMembership>(); loginController = new LoginController(membership.Object); }; protected static Mock<ISiteMembership> membership; protected static LoginController loginController; }

Estoy escribiendo mis primeras especificaciones de MSpec y quería un poco de orientación. Dejé las especificaciones en el estado "pendiente", pero el contexto está completo. ¿Hay alguna mejora por hacer?

Como referencia, esta es la historia y el primer escenario:

Story: "Blog admin logs in to the system" As a blog writer I want to be able to log in to my blog So that I can write posts and administer my blog Scenario: "Logs in from the login page" Given the user enters in correct credentials for a user in the system When the user clicks the "Login" button Then log the user in and redirect to the admin panel with a message stating that he logged in correctly

Y el código de MSpec (algunas partes cortadas), note que tuve que hacer un alias con el delegado de MSpec It debido a un conflicto con Moq.It :

using MoqIt = Moq.It; using ThenIt = Machine.Specifications.It; [Subject("User tries logging in")] public class When_user_enters_valid_credentials : With_user_existing_in_membership { protected static ActionResult result; Because of = () => { result = loginController.Login(validUsername, validPassword); }; ThenIt should_log_the_user_in; ThenIt should_redirect_the_user_to_the_admin_panel; ThenIt should_show_message_confirming_successful_login; } public abstract class With_user_existing_in_membership { protected static Mock<ISiteMembership> membershipMock; protected static string validUsername; protected static string validPassword; protected static LoginController loginController; Establish context =()=> { membershipMock = new Mock<ISiteMembership>(); validUsername = "ValidUsername"; validPassword = "ValidPassword"; //make sure it''s treated as valid usernames and password membershipMock .Setup<bool>(m => m.Validate( MoqIt.Is<string>(s => s == validUsername), MoqIt.Is<string>(s => s == validPassword))) .Returns(true); loginController = new LoginController(membershipMock.Object); }; }