Tenemos una capa de lógica de negocios (BLL) que está estrechamente unida a nuestra capa de acceso a datos (DAL). Hacemos llamadas como esta:
using (FooData data = new FooData())
{
data.DoSomething();
}
Es importante tener en cuenta que todas nuestras clases de datos están internal
y están en el mismo ensamblaje que las clases lógicas, de modo que solo el BLL puede acceder al DAL.
Para desacoplarlos (para ayudar a facilitar las pruebas unitarias), una idea es crear interfaces IDataClass, como IFooData. Al principio pensé que podría ser un problema porque tendríamos que hacer públicas nuestras clases de datos para implementar las interfaces. Pero deberíamos poder mantener las clases de datos internas, a pesar de que todavía necesitamos que los métodos sean públicos:
public interface IFooData
{
void DoSomething();
}
internal class FooData : IFooData // Notice the class is internal
{
public void DoSomething(); // Method is public, but that's ok because class is internal
}
Entonces, aunque el método es público, dado que la clase en sí es interna, deberíamos permitir solo nuestro acceso BLL.
¿Hay algo inherentemente malo con este enfoque? ¿Existe una mejor manera de abstraer el DAL, para pruebas unitarias, sin abrir el DAL al mundo haciéndolo público?
fuente
Respuestas:
Extraer una interfaz y garantizar que BLL esté usando solo tipos de interfaz es una buena manera de hacer que BLL sea comprobable sin la base de datos.
Lo que estás haciendo está absolutamente bien.
fuente
using (IFooData data = new FooData())
en su BLL, realmente no ha realizado ningún cambio, excepto la introducción de la interfaz. Ahora tendrá que encontrar una manera de crear una instanciaIFooData
externa, de lo contrario, sus pruebas BLL seguirán acopladas al DAL.DataAccessFactory.GetDataInterface<IFooData>().DoSomething();
Puede usar el
InternalsVisibleToAttribute
para separar su DAL de su Business Layer, pero aún así mantener los métodos DAL internos. Terminarás creando tu DAL como un ensamblaje amigo .Puede que este no sea un gran enfoque, ya que tendría que especificar en el
Assembly.cs
archivo de su DAL qué ensamblajes pueden acceder al DAL. Entonces todavía hay algo de acoplamiento involucrado (DAL sabe sobre BLL).Entonces, para responder a su pregunta, no hay nada de malo en su enfoque. Pero aprovechar los ensamblajes de amigos puede proporcionarle un poco más de abstracción y probablemente ayudarlo a hacer que su código sea más comprobable.
Espero que esto ayude.
fuente
InternalsVisibleTo
y si necesito mover el DAL a otra asamblea, eso sería de gran ayuda.Pareces inamovible con tus ideas que expusiste en tu pregunta, pero responderé de todos modos; alguien puede encontrarlo útil en algún momento en el futuro.
Si insiste en mantener su DAL interno pero aún desea obtener algunas pruebas unitarias y no le importa usar las herramientas de Pruebas unitarias de Microsoft, intente el enfoque PrivateObject . Este es un contenedor para la reflexión que siempre puede codificar usted mismo, pero le ahorra algunas líneas de escritura.
Tenga en cuenta que el uso de InternalsVisibleTo es un enfoque viable, pero es torpe: si lo está utilizando, es posible que ya esté en un rápido descenso cuesta abajo.
internal
significa que algo es público solo dentro de los límites de su ensamblaje, ese modificador se usa normalmente porque no quieres cosas que se puedan usar desde afueraesa asamblea, entonces rápidamente te das la vuelta y violas ese concepto al declarar un InternalsVisibleTo ... esa es una gran bandera roja sucia que está gritando por alguna refactorización. El desacoplamiento es una pérdida de tiempo cuando solo un ensamblaje llama al otro, también puede pegarlos. El desacoplamiento infiere que múltiples conjuntos están llamando al objetivo (la introducción de pruebas unitarias no cuenta para el 'múltiple' porque hay formas de llegar al conjunto objetivo como ya he mencionado).fuente
InternalsVisibleTo
. No lo estoy usando. Por alguna razón estás asumiendo que lo estoy usando. No entiendo por qué.Técnicamente, su diseño no tiene nada de malo.
Sin embargo, consideraría un enfoque alternativo: en lugar de desacoplar su BLL de su DAL, desacople mejor su DAL de su base de datos. Permita la creación de objetos DAL en la memoria, y si su BLL necesita cargar objetos DAL desde algún lugar, use el patrón de repositorio (vea aquí ) para evitar el contacto directo del BLL con la base de datos. De esa manera, puedes
De hecho, lo que pierde es la capacidad de probar el BLL con simulacros de DAL. Pero en realidad, esos objetos simulados DAL se parecerán mucho a sus objetos DAL reales para proporcionar una base para pruebas útiles del BLL. En mi humilde opinión, evita una gran cantidad de duplicación de código y un esfuerzo innecesario al reutilizar sus objetos DAL reales para pruebas automatizadas de BLL.
fuente
El enfoque de la interfaz es bueno / general para burlarse de su DAL durante las pruebas de consumidores como el BLL.
Sin embargo, una cosa a tener en cuenta es que al hacer que sus clases de concreto DAL sean internas, es posible que esté haciendo que su DAL concreto sea más difícil de probar directamente, ya que esto ahora implica que las pruebas de la unidad DAL también deben estar en este ensamblaje sin necesidad de usar puertas traseras como reflejo
Además, en algún momento en el futuro, puede considerar el uso de un contenedor de IoC para construir la implementación detrás de una interfaz, que también podría tropezar con la interna.
Puede imitar la encapsulación que está tratando de lograr con 'solo interno' agregando una regla de convención / LINT que su BLL / otras capas deben acoplarse al DAL a través de la interfaz, no en la implementación concreta.
fuente