2015-08-13 6 views
10

Sto testando i risultati di una query. La tabella in cui sono archiviati i risultati ha una struttura come questa:È corretto ordinare una lista nel corpo del caso di test per verificare i dati di confine?

Id SomeValue Date  Hour 
----------------------------------- 
1 foo1  2015-01-01 700 
2 foo2  2015-01-01 800 
3 foo3  2015-01-01 900 
... 
18 foo18  2015-01-01 2400 
19 bar1  2015-01-02 100 
20 bar2  2015-01-02 200 
... 
41 bar23  2015-01-02 2300 
42 bar24  2015-01-02 2400 
43 baz1  2015-01-03 100 
44 baz2  2015-01-03 200 
(and on...) 

e la query riceve parametri al fine di fare la ricerca in base a Date e Hour colonne come questo:

SELECT * 
FROM table 
WHERE 
    (date, hour) >= (:dateFrom, :hourFrom) 
    AND (date, hour) <= (:dateTo, :hourTo) 
-- there's no ORDER BY clause in the query 

Ad esempio, se uso i seguenti valori:

  • dateFrom: '2015-01-01'
  • hourFrom: 700
  • dateTo: '2015-01-03'
  • hourTo: 600

La query restituirà tutte le righe in cui il valore di Date è tra 2015-01-01 e 2015-01-03, i valori di hour sono superiore o uguale a 700 solo per Date = 2015-01-01 e i valori di hour sono inferiori o uguali a 600 per Date = 2015-01-03. In questo esempio, tutte le righe con Date = 2015-01-02 verranno recuperate dall'origine dati.

Recupero i risultati dell'esecuzione della query in un elenco. Per valutare i risultati, sto usando i valori dei parametri che ho usato per verificare se i dati nella lista sono conformi a loro. Sto usando un metodo per verificare se la data dell'elemento è compresa tra dateFrom e dateTo, ma mi chiedo come posso verificare i valori di hourFrom e hourTo. Ho le seguenti idee:

  • avviare il controllo per il valore minumum di hour sugli elementi in cui il valore di Date è uguale al mio parametro dateFrom e verificare se questo valore è uguale a hourFrom. Fare lo stesso per hourTo ma con il valore massimo di quelle righe il cui valore di Date è uguale al valore del parametro dateTo.
  • Ordinare l'elenco nel metodo di prova per Date e Hour, quindi controllare il primo e l'ultimo elemento nell'elenco. Il metodo di ordinamento da utilizzare sarà ottenuto dal linguaggio di programmazione che sto utilizzando.

Quale opzione è corretta? Se nessuno, quale sarà la migliore strategia per farlo? Sto usando Java per scrivere i test, ma questa domanda è più focalizzata su come scrivere il metodo di test piuttosto che sulla tecnologia/framework da usare. Inoltre, non posso modificare la query per aggiungere una clausola ORDER BY (che faciliterebbe molto il mio lavoro ma non è fattibile).

Sono preoccupato per le migliori pratiche. Stavo pensando di ordinare i dati, quindi farò asserzioni su due elementi ma poi mi preoccupo se devo testare anche lo Comparator usato per l'ordinamento perché potrebbe ordinare l'elenco in modo errato e il mio test fallirà, controllando ogni elemento manualmente significa usare le dichiarazioni if-else per le asserzioni e non sono sicuro che sia una buona pratica.

risposta

7

Posso vedere come la vostra preoccupazione principale potrebbe essere quella di scrivere un test unitario con la logica più semplice possibile. Fare ciò aumenterebbe il tuo livello di confidenza che quando il test unitario riporta un successo o un fallimento, ciò significa che la query sta restituendo risultati buoni o cattivi, e non che hai codificato un bug nella logica del tuo test unitario. Potrebbe non avere importanza per te avere la migliore performance assoluta.

Se questo è il tuo caso, ti propongo di utilizzare l'opzione n. 1 molto semplice, in cui devi semplicemente controllare ogni data/ora in sequenza, e fallire il test dell'unità non appena incontri una data/orario che non è all'interno la tua data/ora minima/massima. Tuttavia, regolare il metodo di confronto di 2 serie di date/ore nel modo seguente per mantenere la logica di confronto molto semplice:

Concatenare e formattare ogni data/ora nel seguente formato stringa: YYYY-MM-DD hhmm (ad esempio 2015-01-01 0700). In altre parole, la stringa è formattata con lo zero padding richiesto in modo che abbia sempre una lunghezza di 15. Seguendo questo formato ha esattamente la proprietà molto conveniente che se si confrontano 2 tali stringhe usando il metodo integrato String.compareTo(), si confronteranno accuratamente le date.

Questo consente quindi di mantenere la logica molto semplice e leggibile. Ecco un esempio di come potrebbe essere (non hai specificato, quindi presumo che la tua data sia una stringa e il tempo è un numero, ma puoi adattarlo ai tuoi effettivi tipi):

// starting boundary values 
String dateFrom = "2015-01-01"; 
int hourFrom = 700; 
String dateTo = "2015-01-03"; 
int hourTo = 600; 

String formatString = "%s %04d"; // adjust as necessary. 

String fromDateTime = String.format(formatString, dateFrom, hourFrom); 
String toDateTime = String.format(formatString, dateTo, hourTo); 

// execute query here 

while (rs.next()) { 
    String dateTime = String.format(formatString, rs.getString("date"), rs.getInt("hour")); 

    if (fromDateTime.compareTo(dateTime) > 0 || toDateTime.compareTo(dateTime) < 0) { 
     throw new Exception("fail unit test"); 
    } 
} 
+0

Questo sembra interessante e più utile delle mie idee attuali. Ci metterò alla prova domani (attualmente per me alle 8 di domenica) e ti farò sapere come è andata. Grazie. –

2

Entrambe le opzioni proposte sono corrette.L'opzione in cui si ordinano i dati sarà più facile da implementare.

2

Non c'è niente di sbagliato nell'ordinare i risultati dopo averli recuperati. Questo è l'approccio che prenderei, ma il controllo di ogni riga funzionerebbe altrettanto bene.

-1

Vai con l'opzione 1. Mentre si attraversano i dati, registrare i valori massimo e minimo. Puoi attraversare la lista solo una volta. Se il tuo obiettivo è solo quello di trovare un'esistenza di dati non conformi, allora è possibile che tu non possa finire l'attraversamento fino alla fine se ne trovi già uno. Questo è più efficiente dell'ordinamento della lista. Il caso peggiore è O (n).

2

Poiché si tratta di una data, è preferibile utilizzare gli oggetti Date di java;

import java.io.IOException; 
import java.text.ParseException; 
import java.util.Calendar; 
import java.util.Date; 
import java.util.GregorianCalendar; 

public class ATest { 

    public static void main(String[] args) throws IOException, ParseException { 
     String dateFrom = "2015-01-01"; 
     String dateTo = "2015-01-03"; 

     // those are actually string as i see. 
     String hourFrom = "700"; 
     String hourTo = "600"; 


     Date from = str2Date(dateFrom, hourFrom); 
     Date to = str2Date(dateTo, hourTo); 

     Date any = new GregorianCalendar().getTime(); 

     // now testing any date using 'before' 'after' 
     assert(any.after(from) && any.before(to)); 

     // or using compareTo 
     assert(any.compareTo(from) > 0 && any.compareTo(to) < 0); 

     // or simpy comparing epocs, i would use this 
     long low = from.getTime(); 
     long high = from.getTime(); 

     assert(any.getTime() > low && any.getTime() < high); 
    } 

    private static Date str2Date(String date_input, String time_input) { 

     // probably this is an overkill. 
     while (time_input.length() < 4){ 
      time_input = "0" + time_input; 
     } 

     String parts[] = date_input.split("-"); 
     int year = Integer.parseInt(parts[0]); 
     int month = Integer.parseInt(parts[1]); 
     int date = Integer.parseInt(parts[2]); 

     int hourOfDay = Integer.parseInt(time_input.subSequence(0, 2).toString()); 
     int minute = Integer.parseInt(time_input.subSequence(2, 4).toString()); 
     int second = 0; 

     Calendar cal = GregorianCalendar.getInstance(); 
     cal.set(year, month - 1, date, hourOfDay, minute, second); 

     return cal.getTime(); 
    } 
} 

L'ordinamento o meno non è importante per me (se il numero di elementi nell'elenco non è molto alto).