Domanda

sto usando SpecFlow, e mi piacerebbe scrivere uno scenario come il seguente:

Scenario: Pressing add with an empty stack throws an exception
    Given I have entered nothing into the calculator
    When I press add
    Then it should throw an exception

E 'calculator.Add() che sta per generare un'eccezione, così come faccio a gestire questo nel metodo segnato [Then]?

È stato utile?

Soluzione

Grande questione. Io non sono né un esperto di BDD o specflow, tuttavia, il mio primo consiglio sarebbe di prendere un passo indietro e valutare lo scenario.

Vuoi veramente usare i termini "tiro" e "eccezione" in questo spec? Tenete a mente l'idea con BDD è quella di utilizzare un linguaggio onnipresente con il business. Idealmente, essi dovrebbero essere in grado di leggere questi scenari e interpretarli.

pensare di cambiare "quindi" frase di includere qualcosa di simile:

Scenario: Pressing add with an empty stack displays an error
    Given I have entered nothing into the calculator
    When I press add
    Then the user is presented with an error message

L'eccezione è ancora gettato in background, ma il risultato finale è un semplice messaggio di errore.

Scott Bellware tocca questo concetto in questo podcast Codice Herding: http://herdingcode.com/?p=176

Altri suggerimenti

Come un novizio di SpecFlow io non ti dico che questo è il modo per farlo, ma un modo per farlo sarebbe quello di utilizzare il ScenarioContext per memorizzare l'eccezione generata nel < strong> Quando ;

try
{
    calculator.Add(1,1);
}
catch (Exception e)
{
    ScenarioContext.Current.Add("Exception_CalculatorAdd", e);
}

Poi si potrebbe verificare l'eccezione generata e fare afferma su di esso;

var exception = ScenarioContext.Current["Exception_CalculatorAdd"];
Assert.That(exception, Is.Not.Null);

Detto questo; Sono d'accordo con scoarescoare quando dice che si dovrebbe formulare lo scenario in un po formulazioni piu 'business-friendly'. Tuttavia, utilizzando SpecFlow per guidare l'implementazione del dominio-modello, la cattura di eccezioni e facendo afferma su di loro può tornare utile.

A proposito: Partenza screencast di Rob Conery sopra a TekPub per alcuni buoni suggerimenti sull'utilizzo SpecFlow: http: / /tekpub.com/view/concepts/5

BDD può essere praticato sul comportamento livello di funzionalità e / o sul comportamento livello di unità.

SpecFlow è uno strumento BDD che si concentra sul comportamento livello di funzionalità. Le eccezioni non sono qualcosa che si dovrebbe specificare / osservare il comportamento livello di funzionalità. devono essere specificati Eccezioni / osservati sul comportamento a livello di unità.

Pensate di scenari SpecFlow come specifica dal vivo per la parti interessate non tecnico. Si potrebbe anche non scrivere nella specifica che viene generata un'eccezione, ma come si comporta il sistema in questo caso a.

Se non si dispone di parti interessate non tecnici, quindi SpecFlow è lo strumento sbagliato per voi! Non sprecare energie nella creazione di Specifiche leggibili se non c'è nessuno interessato a loro lettura!

Ci sono strumenti BDD che si concentrano sul comportamento livello di unità. In .NET la più popolare è MSpec ( http://github.com/machine/machine.specifications). BDD sull'unità di livello può anche essere facilmente pratiche con sostegno, unit test standard.

Detto questo, si potrebbe ancora verificare la presenza di un'eccezione in SpecFlow .

Qui ci sono alcuni più la discussione di BDD on-livello di unità contro BDD in funzione a livello di: SpecFlow / BDD vs Unit Testing BDD per Test di collaudo contro BDD per i test unitari (o: ATDD vs TDD)

ha anche un'occhiata a questo post del blog: Classifying BDD Tools (vs. Unit-Test-Driven Acceptance test Driven) e un po 'di storia BDD

La modifica lo scenario di non avere un'eccezione è un probabilmente buon modo per avere l'utente scenario più orientato. Tuttavia, se ancora bisogno di avere a lavorare, si prega di considerare quanto segue:

  1. catturare un'eccezione (Consiglio vivamente la cattura di eccezioni specifiche a meno che non si ha realmente bisogno di catturare tutti) nella fase che invoca un'operazione e passarlo al contesto scenario.

    [When("I press add")]
    public void WhenIPressAdd()
    {
       try
       {
         _calc.Add();
       }
       catch (Exception err)
       {
          ScenarioContext.Current[("Error")] = err;
       }
    }
    
  2. Convalida tale eccezione è memorizzato nel contesto scenario

    [Then(@"it should throw an exception")]
    public void ThenItShouldThrowAnException()
    {
          Assert.IsTrue(ScenarioContext.Current.ContainsKey("Error"));
    }
    

P.S. E 'molto vicino a una delle risposte esistenti. Tuttavia, se si tenta di ottenere valore da ScenarioContext utilizzando la sintassi come di seguito:

var err = ScenarioContext.Current["Error"]

si getterà un'altra eccezione nel caso in cui se la chiave "Error" non esiste (e che non riuscirà tutti gli scenari che eseguono calcoli con i parametri corretti). Quindi ScenarioContext.Current.ContainsKey può essere solo più appropriato

Nel caso in cui si stanno testando le interazioni degli utenti lo farò unico consiglio quello che è già stato detto di concentrarsi sulla user experience: "Quindi l'utente è presentato con un messaggio di errore". Ma, nel caso in cui si sta testando un livello inferiore l'interfaccia utente, vorrei condividere la mia esperienza:

sto usando SpecFlow di sviluppare un livello di business. Nel mio caso, non mi interessa circa le interazioni UI, ma ho ancora trovare estremamente utile l'approccio BDD e SpecFlow.

Nel livello aziendale Non voglio specifiche che dicono "Quindi l'utente è presentato con un messaggio di errore", ma in realtà verificando che il servizio risponde correttamente ad un ingresso errato. Ho fatto per un po 'quello che è già stato detto di catturare l'eccezione al "quando" e verifica che al "Allora", ma trovo questa opzione non ottimale, perché se si riutilizza il "Quando" passo si potrebbe ingoiare un'eccezione dove non me l'aspettavo.

Al momento, sto usando esplicite "quindi" clausole, alcune volte senza il "Quando", in questo modo:

Scenario: Adding with an empty stack causes an error
     Given I have entered nothing into the calculator
     Then adding causes an error X

Questo mi permette di codificare in particolare l'azione e il rilevamento delle eccezioni in un unico passaggio. Posso riutilizzarlo per testare il maggior numero di casi di errore come voglio e non mi fa aggiungere il codice non correlato al mancato fallimento "quando" passi.

La mia soluzione comporta un paio di elementi per attuare, ma alla fine si avrà un aspetto molto più elegante:

@CatchException
Scenario: Faulty operation throws exception
    Given Some Context
    When Some faulty operation invoked
    Then Exception thrown with type 'ValidationException' and message 'Validation failed'

Per fare questo lavoro, seguire questi 3 passi:

Passaggio 1

Segna Scenari si aspetta eccezioni con alcuni tag, ad esempio, @CatchException:

@CatchException
Scenario: ...

Passaggio 2

Definire un gestore AfterStep al cambiamento ScenarioContext.TestStatus essere OK. Si può solo voler ignorare gli errori in per Quando passi, in modo da poter ancora fallire un test in Poi verifica un'eccezione. Ha dovuto fare questo attraverso la riflessione come proprietà TestStatus è interno:

[AfterStep("CatchException")]
public void CatchException()
{
    if (ScenarioContext.Current.StepContext.StepInfo.StepDefinitionType == StepDefinitionType.When)
    {
        PropertyInfo testStatusProperty = typeof(ScenarioContext).GetProperty("TestStatus", BindingFlags.NonPublic | BindingFlags.Instance);
        testStatusProperty.SetValue(ScenarioContext.Current, TestStatus.OK);
    }
}

Passaggio 3

Convalida TestError allo stesso modo in cui si validare qualsiasi cosa all'interno ScenarioContext.

[Then(@"Exception thrown with type '(.*)' and message '(.*)'")]
public void ThenExceptionThrown(string type, string message)
{
    Assert.AreEqual(type, ScenarioContext.Current.TestError.GetType().Name);
    Assert.AreEqual(message, ScenarioContext.Current.TestError.Message);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top