2009-09-24 7 views
7

Estamos utilizando un patrón de generador para generar datos de prueba. Estos objetos de dominio tienen relaciones entre ellos. Nuestras pruebas funcionales requieren que estos objetos persistan.Datos complejos de prueba persistentes

Piense en este modelo:

domain model http://i34.tinypic.com/21mg1gn.png

Si quiero un ejemplo sencillo de CI hacer aNew().c().build()

Si yo quiero que sea persistió hago aNew().c().saveIn(session)

Si quiero una instancia de C con un BI conocido do aNew().c().with(b).build()

Bueno, tienes t la idea. Mi problema es, si quiero persistir una C, ¿debería persistir que es B? ¿O debería persistir antes de la mano? ¿Qué pasa si quiero un B por defecto razonable? ¿Qué pasa si quiero persistir una D? ¿Debería persistir todo A, B, C?

Por supuesto, el sistema real es mucho más complejo (a veces con referencias circulares). Estoy buscando una mejor práctica para persistir datos complejos de prueba.

Editar: Parece que he tropezado con la barrera del idioma, mi lengua materna no es el inglés, así que lo siento por la oscuridad. Aquí hay más información:

  • No es el código heredado que estoy tratando de probar
  • Estoy tratando de escribir una prueba de cobertura, no una prueba de unidad (como resultado no voy a burlarse de nada)
  • El software que estoy tratando de probar funciona si la base de datos está poblada hasta cierto punto (no usa todas las entidades).

PS. No dude en solicitar más información, porque he estado luchando por encontrar la mejor práctica posible. Lo más parecido que se me ocurre es:

  1. Mantenga un registro de lo que se ha establecido explícitamente al crear una entidad.
  2. Suponga que las entidades explícitamente establecidas ya están persistentes, no las persista.
  3. Persista todo lo demás (con su propia persistencia).

Esto funcionará, pero mi sensación de araña es un hormigueo, creo que estoy haciendo algo mal, porque habrá una lógica involucrada en el código de prueba, será muy complejo tratar sin pruebas.

Editar 2: Intentaré ser más claro. Cuando estoy escribiendo/ejecutando mi unidad y algunas pruebas de integración no tengo ningún problema, porque los datos de la prueba no se conservan, sino que permanecen en la memoria.

Pero cuando intento persistir en mis datos de prueba, hibernar no me permite guardar una entidad sin sus relaciones.

¿Cómo puedo solucionar este problema?

Respuesta

1

Es necesario definir sus cascadas en el dominio mejor. Si no puede probarlo, ¿cómo espera que funcione en la aplicación real?

Por ejemplo:

A -> B: ¿Quién es el dueño de esta relación? ¿Quieres agregar B a A, o al revés? Esto puede ser un detalle de implementación donde puede tener B.SetParent (A) y A.Children.Add (B), y donde establece el padre de B en A en el caso de A.Children.Add (B) (de la misma manera que el otro a su alrededor). Qué sucede si lo hace:

A a1 = new A(); 
A a2 = new A(); 
B b = new B(); 
a1.Children.Add(b); 
b.SetParent(a); 

Tiene que decidirse aquí. Ninguna de las soluciones es perfecta, por lo que es básicamente la preferencia personal y la coherencia de la aplicación que se aplica aquí.

Trabajando con ORMs obtienes estos problemas de restricción más rápido que con SQL simple (o cualquier otra fuente de datos como XML o tu propia fuente de datos), pero necesitarías considerar los problemas si también escribes SQL simple.

Disculpa, no tengo una respuesta definitiva para ti, pero para mí parece que debes considerar algunas limitaciones que (supongo) aún no has hecho.

Personalmente, me gusta el repositorio-patrón cuando se trata de usar NHibernate en DALs. Hago que mis repositorios implementen desde IDisposable y les dejo una sesión cada uno. De esta manera, obtendrá la "unidad de trabajo" -patrón en su diseño.

Buena suerte con él :)

3

Probablemente deba describir la configuración de su prueba con más detalle.En particular, ¿por qué sus pruebas funcionales requieren que estos objetos persistan? ¿Estás probando la operación de persistencia real? ¿O es solo un efecto secundario de ejecutar las pruebas? ¿Desea cargar objetos persistentes como parte de sus pruebas?

Mi problema es que, si quiero persistir una C, ¿debería persistir es B? ¿O debería persistir antes de la mano?

Esto dependerá de por qué usted persiste en primer lugar. Si está realizando pruebas de integración en la capa de persistencia, entonces debería usar la lógica que usa la aplicación. Si es solo un efecto secundario de la prueba, es posible que desee simular la capa de persistencia, etc. ...

+0

Imagine que estos datos ya existen en la base de datos. Y otro proceso (que estoy probando) es leer estos datos. Pero a veces, una B es relevante y quiero que sea visible en la prueba al crear y persistir Bs; pero a veces no son relevantes y estoy tratando de esconderlos detrás de los constructores. – nimcap

+0

Eso no tiene sentido para mí. Si los datos ya están en la base de datos, ¿por qué (y quién) necesita persistir? ¿Y a qué te refieres con "quiero que [B] sea visible en la prueba"? – sleske

0
  • ¿Qué le dicen sus pruebas?
  • ¿Parece que está probando una aplicación heredada?
  • ¿Así que su funcionalidad de tomar ya está escrita en su código base y está tratando de crear una prueba de cobertura?

darnos más retroalimentación favor

1

que separa sus respuestas por tema.

Mi problema es, si quiero que persista un C, si persiste es B? ¿Qué pasa si quiero persistir una D? ¿Debería persistir todo A, B, C?

Esto depende completamente de las restricciones de dominio que elija aplicar.Por ejemplo, ¿es C una entidad y B un objeto de valor? En otras palabras, ¿el C tiene una identidad y vida únicas? ¿Está identificado el B principalmente por su valor y su ciclo de vida estrechamente acoplado al de su matriz C?

Hacer este tipo de preguntas debería ayudar a guiar sus decisiones sobre qué persistir, cuándo y por quién.

Por ejemplo, si ambos C y B son entidades que comparten una relación única, puede decidir a persistir ellas forma independiente, ya que cada uno podría concebiblemente tener una vida con sentido e identidad propia. Si B es un objeto de valor, probablemente elija que su entidad padre C controle su duración, incluida la creación/recuperación/actualización/eliminación del objeto. Esto bien podría incluir C persistiendo B.

¿O debe persistir de antemano?

Para responder a esto, podría tener que mapear sus dependencias de objeto. Estas dependencias suelen estar representadas por restricciones de clave externa cuando un gráfico de objetos persiste en un RDBMS. Si C no pudo funcionar sin una referencia a B, entonces es probable que desee conservar ambas dentro de una transacción, con B primero para cumplir con las restricciones de la clave externa de la base de datos. Siguiendo la línea de pensamiento anterior, si B era una entidad secundaria o el valor objetivo de C, que incluso podría tener C responsables de la persistencia de B.

¿Qué tal si quiero un B por defecto razonable?

La creación de B casos podría ser delegada en el B -Factory. Ya sea que implementes esta lógica de fábrica como un método de clase (no instancia), constructor, o la separes como su propia unidad no importa. El punto es que tiene un lugar donde se lleva a cabo la creación y configuración de la nueva B s. Es en este lugar donde tendrá lugar una configuración predeterminada del objeto recién instanciado.

Un excelente recurso que cubre este tipo de preguntas es Domain-Driven Design por Eric Evans

+0

No pude decidir cuál aceptar, el otro vino antes ... así que lo siento, ojalá hubiera una manera de aceptar respuestas múltiples – nimcap

1

No estoy seguro de haber entendido el problema que está tratando de resolver muy bien pero ... ¿qué pasa con la serialización de todo el gráfico como XML utilizando algo así como XStream o Google Protocol Buffers?

+0

Buzón de protocolo de Google agregado como favorito –

0

Por lo que yo veo, el problema es con su dominio (como lo ha dibujado). Por lo que yo entiendo, C tiene una relación de muchos a uno con B, y la base de datos lo está enfocando mediante un campo de clave externa no anulable.Por otro lado, a partir del código en la pregunta, pude entender que no existe una aplicación de la regla exactamente una en el código, y el miembro que hace referencia a la instancia B en la instancia C puede ser nulo. Por lo que yo entiendo, el modelo de dominio debe ser siempre correcto en código y en tiempo de ejecución, por lo que si esta regla se hubiera aplicado en el código (exigiendo una referencia B en el método C build(), por ejemplo) no tendrías cualquier problema con la persistencia, podrías simplemente persistir todo.

Otra solución, mucho más sucia, sería simplemente eliminar de forma programática todas las limitaciones de DB que ensucian sus pruebas antes de la prueba y restaurarlas después. Por supuesto, haría que la base de datos fuera completamente inutilizable para cualquier otra cosa que se ejecutara en paralelo a la prueba, pero esto se puede resolver utilizando una base de datos interna tal como SQLite o SQL Server Compact Edition solo para las pruebas.

Cuestiones relacionadas