funzione di refactoring per avere un design robusto

4

Sto avendo un semplice esempio di app qui:

di avere questo codice che gestisce le richieste dell'utente per ottenere un elenco di libri memorizzati in un database.

from .handlers import all_books
from flask import jsonify

@apps.route('/show/all', methods=['GET'])
@jwt_required
def show_books():
    user_name = get_jwt_identity()['user_name']
    books = all_books(user_name=user_name)
    return jsonify(books), 200

e in handlers.py ho:

def all_books(user_name):
        db = get_db('books')
        books = []
        for book in db.books.find({'read_by':user_name}):
            books.append(book)
        return books

ma durante la scrittura di unit test ho realizzato che se utilizzo get_db() in all_books() sarebbe più difficile testare il metodo unitario. quindi ho pensato che sarebbe stato il modo migliore.

from .handlers import all_books

@apps.route('/show/all', methods=['GET'])
@jwt_required
def show_books():
    user_name = get_jwt_identity()['user_name']
    db = get_db('books')
    collection = db.books
    all_books(collection=collection,user_name=user_name)

def all_books(collection,user_name):
        books = []
        for book in collection.find({'read_by':user_name}):
            books.append(book)
        return books

voglio sapere qual è il buon design da usare? avere tutto il codice facendo una cosa in un posto come il primo esempio o il secondo esempio è buono.

Per me il primo sembra più chiaro in quanto ha tutta la logica correlata in un unico posto. ma è più facile passare una raccolta falsa nel secondo caso per testare l'unità.

    
posta anekix 19.12.2018 - 12:24
fonte

3 risposte

3

Quando dividi la query db dalla logica del filtro in questo modo ...

def all_books(user_name):
        db = get_db('books')
        return filter_books_by_user(db.books,user_name)

def filter_books_by_user(collection,user_name):
        books = []
        for book in collection.find({'read_by':user_name}):
            books.append(book)
        return books

... ottieni entrambi - una funzione filter_books_by_user che contiene la "logica", ma nessun accesso al database e una funzione all_books che incapsula la query db insieme alla logica del filtro. filter_books_by_user può essere unità testata senza il DB, all_books tuttavia è probabilmente meglio validato da un test di integrazione (incluso il DB).

    
risposta data 20.12.2018 - 08:38
fonte
1

Il fatto è che c'è una parte IO (interrogare un database, una richiesta http, operazioni di lettura / scrittura del disco locale, ecc.) e c'è una logica di post-elaborazione: filtraggio, ordinamento, convalida. Non ha molto senso testare l'IO attraverso i test unit : i test di integrazione sono stati progettati per questo scopo e tuttavia dimostrano che il database o qualsiasi altro oggetto IO con cui si ha a che fare è lì e risponde come previsto . Tuttavia, sicuramente non significa che non dovresti separare la tua logica pure da un IO: è ciò che può essere facilmente testabile (purché il tuo database sia deriso). Quindi dividilo e copri la parte pura con i test unit , supponendo che la parte IO funzioni correttamente.

    
risposta data 20.12.2018 - 10:43
fonte
0

È comprensibile che tu voglia testare tutto, anche se non è una buona idea. La funzione all_books non contiene alcuna logica aziendale, è solo una delle centinaia di modi per ottenere tutti i libri nel database.

Questo dovrebbe essere testato con test di integrazione, mostrando che i libri sono correttamente restituiti usando il database.

Potresti testare questa funzione unitamente, ma ciò significherebbe creare un oggetto fittizio del database che avresti iniettato e quindi verrai con un test di for in . E se non pianifichi di cambiare i tuoi database in futuro (cosa che non succede mai), è inefficace e inutile.

    
risposta data 19.12.2018 - 12:46
fonte

Leggi altre domande sui tag