2010-06-26 17 views
5

Sto iniziando a passare attraverso le domande nel progetto Euler, e mi piacerebbe avvicinarlo con uno stile TDD, ma ho difficoltà a trovare la risposta numerica alla domanda che non includere il codice C'è qualche risorsa con quei dati in modo che io possa fare test case che mi diranno se ho risolto il problema correttamente?Test di unità per progetto Euler

La mia motivazione è che mi sento come se l'algoritmo fosse la risposta, non il numero. Se guardo l'esempio di codice di qualcun altro, rovina la sfida di capire come per risolvere il problema.

Modifica: sto cercando in particolare il numero della risposta senza contesto o algoritmo con esso in modo che io possa fare qualcosa di simile al seguente. So che è più dettagliato, ma mi piacerebbe essere in grado di avere un risultato pass/fail per dirmi se il mio algoritmo è corretto o meno, piuttosto che guardare l'esempio di codice di qualcun altro per sapere se l'ho fatto correttamente.

import unittest 
class ProblemOneTest(unittest.TestCase): 
    def test_me(self): 
     self.assertEquals(solve_problem_one(),233168) 

if __name__ == '__main__': 
    print "Problem 1 possible answer: %d" % solve_problem_one() 
    sys.exit(unittest.main()) 
+0

Avere delle risposte rovinerebbe la sfida in parte. Quello che potresti fare è eseguire più "soluzioni" e confrontare il loro output. –

+2

Per me provo il contrario. Il numero non ha senso senza l'algoritmo. Sento che il codice stesso è la risposta e vedere come qualcun altro ha rovinato la sfida di capire * come * risolverlo. – Daenyth

+3

Non sta inserendo il numero nella pagina del contex e ottenendo il "lo hai risolto!" schermo sufficiente? Non vedo davvero come i test unitari possano dare qualche aiuto lì. Prova invece a scrivere algoritmi diversi, modificali per renderli più veloci o semplicemente più eleganti. – nico

risposta

4

La pagina del problema sul sito Web del progetto Euler ha un input per verificare la risposta. Questo è tutto ciò di cui ho veramente bisogno.

11

TDD e progetto Gli incarichi di Eulero non vanno necessariamente bene insieme. In primo luogo, TDD non ti aiuterà a risolvere i problemi di Eulero (PE) del progetto. Questo mi ricorda il ben noto tentativo da parte di un ragazzo di "risolvere il Sudoku" di using TDD.

TDD non è una tecnica di progettazione. Può essere molto utile quando applicabile, ma non pensarlo come un proiettile d'argento.

Un problema di PE in genere comporta un calcolo pesante che termina in un singolo numero, che è la risposta. Per applicare mentalmente TDD, consiglio di usarlo per le utilità matematiche che svilupperai come parti dei tuoi sforzi per risolvere i problemi di PE. Ad esempio, il mio modulo utils per PE consiste in funzioni per il calcolo dei numeri primi, la suddivisione dei numeri in cifre, il controllo dei palindromi e così via. Questo modulo ha una serie di test, poiché queste funzioni sono generali sufficienti per essere testate. Le stesse soluzioni PE non hanno test - l'unico vero test necessario per loro è quello di generare la risposta corretta.

+0

Scusa, avrei dovuto rendermi più chiaro. Sto cercando il numero da solo senza contesto in modo che possa fare qualcosa come "assertEquals (my_solution(), expected_answer)'. Aggiornerò la domanda – Daenyth

+0

test di scrittura +1 per problemi di Project Euler solo ha senso se hai già la risposta e vuoi ottimizzarla. –

+1

È possibile testare l'algoritmo per risolvere il problema con un limite inferiore rispetto a un valore derivato dalla forza bruta (l'ho fatto spesso). – starblue

1

Il test di unità È la risposta.

I problemi di solito sono così semplici (non in termini di difficoltà, ma almeno di impaginazione del codice) che suddividerli in vari metodi/classi di solito sono sciocchi.

+0

Suppongo che sia eccessivo, ma è anche motivato dal voler imparare come usare i test unitari in python. Mi piace anche essere in grado di controllare il mio lavoro senza fare riferimento al codice di qualcun altro. Fondamentalmente voglio solo avere una dichiarazione corretta/errata relativa al mio algoritmo. – Daenyth

+0

Non posso dire di essere completamente d'accordo. In parte nelle domande precedenti, questo è vero per essere sicuro. Ma poiché le cose diventano più complesse e hai bisogno di suddividere ulteriormente i componenti, avrai bisogno/vuoi testare i singoli componenti. Certo, alcune persone possono scrivere un programma molto breve per rispondere alle domande e in tal caso la risposta è giusta, ma la maggior parte dei popoli (umani) romperà il problema in parti più piccole. –

2

Sì, è possibile impostare il test di unità contro i dati del test che dare.

Sembra che tu stia usando Python per risolvere i problemi (come lo sono io). Quello che faccio per convalidare i diversi componenti è fare semplici istruzioni 'assert' rispetto ai dati di esempio. Funziona bene e c'è meno tempo in testa. Inoltre, non è necessario eseguire l'intera suite di test quando si ha solo bisogno di sapere se le nuove modifiche per il problema 30 sono corrette.

Using Assertions Effectively

+0

So che sono quasi 3 anni in ritardo per la festa, ma questa è la strada da percorrere. – chucksmash

1

Lo so, sono 3 anni di ritardo alla festa, ma ho pensato che avrei condiviso come mi sto avvicinando Project Euler via TDD.

Sto lavorando su Python, se questo è importante per te.

Quello che faccio è questa:

  • Ogni problema ottiene (come minimo) la propria funzione che serve come punto di ingresso/uscita, non importa quanto banale o stupido può sentire. I problemi possono anche ottenere funzioni di aiuto se il problema richiede qualche tipo di funzionalità che pensi possa essere necessario in futuro.
  • La maggior parte delle domande di Project Euler include un problema di prova/test più piccolo nel test stesso. Questo problema di test illustra ciò che risolve di più, ma su una scala più piccola.
  • Pianificare l'impostazione della funzione di entrata/uscita con un parametro che consente alla funzione di risolvere sia la versione giocattolo del problema sia la versione a fondo scala più dura. Ad esempio, su problem 12 il mio punto di ingresso (ridicolmente chiamato) è get_triangle_num_with_n_or_more_divisors (n).
  • A questo punto non ho implementato la funzione, l'ho appena chiamata. Ora scriverò due test per questo problema: test_example e test_problem. Per ora decorerò test_problem con @unittest.skip('Unimplemented') poiché non conosciamo la risposta. Il file di prova potrebbe essere qualcosa come il mio:

    import unittest 
    
    from problems.p0014 import get_triangle_num_with_n_or_more_divisors 
    
    class TestHighlyDivisibleTriangleNumber(unittest.TestCase): 
        def test_example(self): 
         self.assertEquals(get_triangle_num_with_n_or_more_divisors(1), 
              1) 
         self.assertEquals(get_triangle_num_with_n_or_more_divisors(2), 
              3) 
         self.assertEquals(get_triangle_num_with_n_or_more_divisors(6), 
              28) 
    
        @unittest.skip('Unimplemented') 
        def test_problem(self): 
         self.assertEquals(get_triangle_num_with_n_or_more_divisors(500), 
              'TODO: Replace this with answer') 
    

Ora si stanno facendo Project Euler, stile TDD. Stai usando i casi di esempio dati per testare il tuo codice di implementazione. In realtà, l'unico trucco è scrivere la tua implementazione in modo sufficientemente flessibile da poter essere utilizzata per risolvere sia la versione pratica che la versione reale.

Mi siedo e scrivo get_triangle_num_with_n_or_more_divisors. Una volta passato test_example, cerco di risolvere il vero problema; se funziona aggiorno il mio caso test_problem con la risposta reale e bam hai un test di regressione completo per l'avvio.

0

ho pensato di condividere il mio approccio:

Hackerrank, che ha un Project Euler section, va sotto il paradigma TDD. Segna il tuo algoritmo usando casi di test sconosciuti. Forniscono un esempio di test per iniziare. Sviluppo offline e scrivo altri casi di test per convalidare la mia soluzione per ottenere un feedback più rapido e preciso.

Dove si possono ottenere quei casi? Puoi farli a mano e magari generarli dal tuo codice di forzatura bruto che viene eseguito localmente. La bellezza di questo è che devi tener conto dei casi limite, che è più tipico di uno scenario di vita reale.

Esempio di test in JavaScript:

var cases = [ 
    {input: '1\n15', output: '45'}, 
    ... 
]; 

describe('Multiples of 3 and 5', function() { 
    cases.forEach((v, i) => { 
    it('test case #' + i, function() { 
     assert.equal(unit(v.input), v.output); 
    }) 
    }); 
}); 

Sebbene Hackerrank utilizza stdin e stdout, ancora cercare di isolare il codice principale in una funzione e impiegano programmazione funzionale.