Skip to content

Latest commit

 

History

History
149 lines (104 loc) · 5.39 KB

when-to-use-plan.md

File metadata and controls

149 lines (104 loc) · 5.39 KB

Nota del traduttore

Questa è la traduzione del file when-to-use-plan.md. Qui c'è il link dove si confrontano le differenze tra commit di riferimento di questa traduzione e l'ultimo commit di AVA sul branch master (Se si clicca sul link, e non si vede il file when-to-use-plan.md nella lista dei file modificati, questa traduzione è aggiornata).


Quando usare t.plan()

Traduzioni: Español, Français, Italiano, 日本語, Português, Русский, 简体中文

Una delle differenze sostanziali tra AVA e tap/tape è il comportamento della funzione t.plan(). In AVA, t.plan() è solamente usato per verificare che il numero previsto di asserzioni sia rispettato, ma non termina automaticamente il test.

Uso superficiale di t.plan()

Molti utenti venendo da tap/tape sono abituati ad usare t.plan() abbondantemente in ogni test. In ogni caso, in AVA, non viene considerato una "buona pratica". Invece t.plan() dovrebbe essere usato in scenari dove potrebbe realmente aggiungere valore al test.

Test sincroni senza ramificazioni

Non è necessario usare t.plan() nella maggior parte dei test sincroni.

test(t => {
	// Sbagliato: non c'è alcuna ramificazione qui - t.plan() non è utile
	t.plan(2);

	t.is(1 + 1, 2);
	t.is(2 + 2, 4);
});

t.plan() non fornisce alcun valore aggiunto in questo caso, ma aggiunge solo difficoltà se volessi decidere di aggiungere o rimuovere un'asserzione.

Promesse che ci si aspetta siano risolte

test(t => {
	t.plan(1);

	return somePromise().then(result => {
		t.is(result, 'foo');
	});
});

Ad una prima occhiata questo test sembra usare giustamente t.plan() dato che un handler per una promessa asincrona è coinvolta. Ci sono però alcuni problemi con il test:\

  1. Probabilmente t.plan() è stato usato per proteggersi contro la possibilità che somePromise() potrebbe essere rifiutata; Restituire una promessa rifiutata farebbe fallire il test in ogni caso.

  2. Sarebbe meglio sfruttare la funzionalità async/await;

test(async t => {
	t.is(await somePromise(), 'foo');
});

Promesse con un handler .catch()

test(t => {
	t.plan(2);

	return shouldRejectWithFoo().catch(reason => {
		t.is(reason.message, 'Hello');
		t.is(reason.foo, 'bar');
	});
});

In questo caso t.plan() viene usato per assicurarsi che il codice nel blocco catch venga eseguito.

Un'alternativa migliore può essere l'utilizzo di t.throws() e async/await, poichè il codice diventa più semplice da leggere e comprendere:

test(async t => {
	const reason = await t.throws(shouldRejectWithFoo());
	t.is(reason.message, 'Hello');
	t.is(reason.foo, 'bar');
});

Assicurarsi che un blocco catch venga eseguito

test(t => {
	t.plan(2);

	try {
		shouldThrow();
	} catch (err) {
		t.is(err.message, 'Hello');
		t.is(err.foo, 'bar');
	}
});

Come già detto nellesempio precedente, è meglio utilizzare t.throws() con async/await.

Uso appropriato di t.plan()

t.plan() aggiunge valore ai tuoi test nei casi seguenti.

Assicurati che callback multiple vengano eseguite

test.cb(t => {
	t.plan(2);

	const callbackA = () => {
		t.pass();
		t.end();
	};

	const callbackB = () => t.pass();

	bThenA(callbackA, callbackB);
});

Il codice sopra verifica che callbackB sia chiamata prima (ed una sola volta), seguita poi da callbackA. Ogni altra combinazione non soddisferebbe la soglia impostata.

Test con raminificazioni

In molti scenari, è una cattiva idea usare complicate ramificazioni nei tuoi test. Un'eccezione particolare riguarda i test che vengono generati automaticamente (per esempio da un file JSON). Qui sotto t.plan() è usato per garantire la conformità dell'input JSON:

const testData = require('./fixtures/test-definitions.json');

testData.forEach(testDefinition => {
	test(t => {
		const result = functionUnderTest(testDefinition.input);

		// testDefinition dovrebbe avere solo uno tra `foo` o `bar` ma non entrambi
		t.plan(1);

		if (testDefinition.foo) {
			t.is(result.foo, testDefinition.foo);
		}

		if (testDefinition.bar) {
			t.is(result.bar, testDefinition.foo);
		}
	});
});

Conclusioni

Ci sono molti usi validi per t.plan(), ma questo non vuole dire che può essere usato in modo indiscriminato. Una semplice regola da seguire è usarlo ogni volta che il tuo test non ha un codice con un flusso diretto o facile da comprendere. I testi con asserzioni dentro callback, blocchi if/then, blocchi for/while e (in certi casi) try/catch sono tutti buoni candidati per l'uso di t.plan().