Can Root Factory di aggregazione può creare la radice e le sue classi interne?

0

Attualmente, i miei aggregati e oggetti valore hanno costruttori protetti e alcuni di essi vengono creati da metodi di factory static all'interno dell'aggregato con nomi descrittivi. Crea un bel DSL e un modello abbastanza incapsulato ma rende il test dell'unità doloroso (se la creazione del modello di dominio fallisce, anche il gestore di servizio / comando verrà contrassegnato come fallito) . L'introduzione dei metodi di fabbrica d'altra parte per ciascuna entità e l'oggetto valore mi obbliga a iniettare un'interfaccia di fabbrica per oggetto entità / valore nel servizio.

È corretto creare un servizio di fabbrica per radice aggregata con un metodo factory per oggetto entità / valore? Ecco un esempio di un servizio factory che crea una radice aggregata aziendale, ed è entità interne / VO:

public class CompanyFactory : ICompanyAggregateRootFactory
{
    public Company CreateCompany(...){}
    public Employee CreateEmployee(...){}
    public CEO CreateCEO(...){}
    ....

}

Esiste un altro modo in cui viene applicato lo stesso livello di incapsulamento e DSL di chiarezza senza che l'unità si collauda l'una sull'altra?

    
posta Mohsen 30.07.2018 - 11:57
fonte

3 risposte

1

L'IMO che fa un TDD esterno non è un motivo valido per introdurre il tipo di "servizio di fabbrica" che hai citato.

  • Se la costruzione di un oggetto dominio richiede una logica complicata (come compilarla da più fonti diverse), allora potrebbe valere la pena mettere tale logica in una classe Factory separata. Puoi prendere in giro quella classe nei test, se lo desideri, ma non è necessario creare una facciata di creazione aggiuntiva.

  • Se si tratta di semplici assegnazioni valore-campo, la logica è probabilmente soggetta alla ragionevole responsabilità dell'oggetto stesso. Non cercare di deriderlo. Solo perché non lo prendi in giro non significa che si rompa all'esterno - in TDD . La creazione di un oggetto di cui hai bisogno, in qualsiasi fase di un processo TDD esterno, è legittima.

all of your service layer tests are being failed as long as you are not implemented the static factory method

Ma aggiungere un ulteriore livello di "Factory Service" non aggiunge alcun valore e non è la soluzione. Mostra solo che il tuo servizio applicativo è in grado di parlare con un livello che prima non esisteva.

Implementare un'entità minima e il suo costruttore è un lavoro abbastanza piccolo da permetterti di passare i test del livello di servizio con lo stesso sforzo, o anche meno, di scrivere un'interfaccia di creazione e prenderla in giro.

Inoltre, l'asserzione tipica nei test esterni quando si crea qualcosa è spiare un repository o un oggetto di accesso ai dati per sapere se l'oggetto ha ricevuto la nuova cosa da memorizzare. Questo disinnesta il dibattito sul "metodo di costruzione interno vs un'interfaccia di fabbrica dedicata" per quanto riguarda i test, perché non è lì che si esercitano i test.

Come nota a margine, alcuni people consiglia di evitare completamente il mocking degli oggetti del dominio (ovvero di deridere solo i limiti architettonicamente significativi).

    
risposta data 30.07.2018 - 16:04
fonte
3

makes the unit testing painful

Parte della motivazione per lo sviluppo del "primo test" è l'euristica che i test imbarazzanti implicano interfacce scomode - se scrivere i client di test è doloroso, questo è un suggerimento (ma non necessariamente una promessa) che la scrittura dei clienti di produzione sarà anche dolorosa.

Is it ok to create a factory service per aggregate root with a factory method per aggregate/value object?

Probabilmente vuoi dire "con un metodo factory per entità / oggetto valore" - normalmente abbiamo una o più entità per aggregato, ma la nidificazione di più aggregati non è un modello comune.

E sì, se pensi che l'interfaccia sia più facile da usare, allora va bene, vai avanti.

Is there any other way which enforces the same level of encapsulation and DSL clarity without making the unit tests depending on one another?

Potresti ottenere un po 'più di separazione utilizzando le interfacce di ruolo per descrivere le diverse parti dell'API. Ad esempio, se stiamo scrivendo un test unitario sui CEO, non ci interessa molto della capacità di creare altre entità. Quindi potremmo preferire

interface ICreateCEO {
    CEO createCEO(...);
}

class CompanyFactory implements ICreateCEO ... {
    CEO createCEO(...);
}

Ma questo è sicuramente "potrebbe", piuttosto che "dovrebbe" - le interfacce "extra" non sono libere da mantenere, quindi vuoi essere sicuro di ottenere un risarcimento da qualche parte.

    
risposta data 30.07.2018 - 12:51
fonte
-1

Statico è quasi sempre una parolaccia. Cerca di non digitarlo.

Dovresti essere in grado di consentire l'iniezione e avere anche una fabbrica predefinita, dato che non ti interessa collegare una fabbrica al tuo tipo aggregato

public class Service
{
    public Service(IFactory fac = new MyFactory()) {...}
}

Ora puoi saltare l'iniezione nella tua applicazione e iniettare una simulazione nei tuoi test

    
risposta data 30.07.2018 - 12:07
fonte