Burlándose de uso Moq en c#

Tengo el siguiente código:

public interface IProductDataAccess
{
    bool CreateProduct(Product newProduct);
}

Clase ProductDataAccess implementa esa interfaz.

public class ProductBusiness
{
    public bool CreateProduct(Product newProduct)
    {
        IProductDataAccess pda = new ProductDataAccess();
        bool result = pda.CreateProduct(newProduct);
        return result;
    }
}

En este caso, cómo crear pruebas unitarias para CreateProduct método por el que se burlaba de la IProductDataAccess interfaz? Pensé en tener una instancia pública de IProductDataAccess dentro de ProductBusiness y se inicializa utilizando Mock<IProductDataAccess> objeto, pero no es una buena práctica para exponer los datos de acceso a la capa de interfaz de usuario. ¿Puede alguien ayudarme?

4 Kommentare

  1. 38

    Clásico ejemplo que demuestra que, si no puedes unidad de prueba de un componente en particular, REFACTORIZARLO!

    Esta es la razón por la que me encanta lo que cualquier burla marco impone a hacer – escribir código desacoplado.

    En tu ejemplo, la ProductBusiness clase está estrechamente ligado con el ProductDataAccess clase. Usted podría separar utilizando (como la mayoría de las respuestas sugieren) la inyección de dependencia. Al hacerlo, se terminaría dependiendo de la IProductDataAccess abstracción y no en cualquier aplicación concreta de la misma.

    Otro punto a tener en cuenta, cuando usted está escribiendo ensayos, especificaciones para la capa de negocio, que normalmente se desea probar el «comportamiento» y no el «estado». Así que, aunque usted podría tener afirma que comprobar si es «true» ha devuelto, las pruebas deben realmente a prueba en caso de que el acceso a los datos de las llamadas que fueron establecidas utilizando MOQ eran realmente ejecutado con la .Verify API de MOQ.

    Trate de añadir el comportamiento de las pruebas donde se espera una excepción (utilizando el «.Lanza» de la API) por la capa de acceso a datos y comprobar si necesita tratamiento especial en la capa de negocio.

    Como Kevin sugiere, la siguiente implementación de ProductBusiness va a trabajar:

    public class ProductBusiness
    {
      private readonly IProductDataAccess  _productDataAccess;
    
      public ProductBusiness(IProductDataAccess productDataAccess)
      {
          _productDataAccess = productDataAccess;
      }
    
      public bool CreateProduct(Product newProduct)
      {
        bool result=_productDataAccess.CreateProduct(newProduct);
        return result;
      }
    }

    y el uso de cualquier xunit marco de pruebas para escribir la prueba como:

     var mockDataAccess = new Mock<IProductDataAccess>();
     mockDataAccess.Setup(m => m.CreateProduct(It.IsAny<Product>())).Returns(true);
     var productBusiness = new ProductBusiness(mockDataAccess.Object);
     //behavior to be tested
  2. 22

    Se debe inyectar IProductDataAccess, como una interfaz de dependencia:

    public class ProductBusiness
    {
        private IProductDataAccess _productDataAccess;    
    
        public ProductBusiness(IProductDataAccess productDataAccess)
        {
            _productDataAccess = productDataAccess;
        }
    
        public bool CreateProduct(Product newProduct)
        {
            bool result = _productDataAccess.CreateProduct(newProduct);
            return result;
        }
    }

    Luego de que se puede reemplazar con un simulacro en sus pruebas:

    var productDataAccess = new Mock<IProductDataAccess>();
    var productBusiness = new ProductBusiness(productDataAccess.Object);
  3. 9

    Con la forma en que se han diseñado actualmente su ProductBusiness clase no hay manera de cambiar la IProductDataAccess su ejecución a través de una maqueta. Un modelo recomendado para esto es donde se toman las dependencias de un tipo a través del constructor. Así que la clase se convierte en:

    public class ProductBusiness
    {
      private readonly IProductDataAccess  _productDataAccess;
    
      public ProductBusiness(IProductDataAccess productDataAccess)
      {
          _productDataAccess = productDataAccess;
      }
    
      public bool CreateProduct(Product newProduct)
      {
          bool result = _productDataAccess.CreateProduct(newProduct);
          return result;
      }
    }

    Ahora estás en una posición de prueba de su clase mediante el uso de un marco de trabajo ficticios como . Por ejemplo:

    var mockDataAccess = new Mock<IProductDataAccess>();
    mockDataAccess
        .Setup(m => m.CreateProduct(It.IsAny<Product>()))
        .Returns(true);
    
    var productBusiness = new ProductBusiness(mockDataAccess.Object);
    //... test behaviour here

    Ahora usted puede cambiar la forma de la maqueta se comporta en su paso de instalación y asegúrese de que su CreateProduct método se comporta correctamente.

    También me gustaría mirar un marco de inserción de dependencia como . Una inyección de dependencia marco puede resolver automáticamente las dependencias de significado la creación de un nuevo tipo es mucho más fácil, ya que no tienen manualmente nuevo todo. También significa que usted puede cambiar la aplicación que se utiliza en un lugar y cambios en todas partes.

    • He seguido los pasos que se indican anteriormente. Hasta entonces, llama a la CreateProduct(Producto newProduct) método definido en ProductDataAccess y es tirar algunos conectividad de base de datos de excepciones.
    • Creo que necesitas un par de paréntesis en: mockDataAccess.Setup(m => m.CreateProduct(It.IsAny<Product>())).Returns(true);
  4. 6

    Usted no debe crear una instancia de un hormigón ProductDataAccess en el interior de su CreateProduct método.
    En su lugar, IProductDataAccess debe ser un inyectable dependencia. Esto se puede hacer en una de dos maneras:

    Propiedad de la inyección:

    public class ProductBusiness
    {
        IProductDataAccess Pda {get; set;}
    }
    
    var productBusiness = new ProductBusiness();
    productBusiness.Pda = new ProductDataAccess();
    productBusiness.Pda = new MockProductDataAccess();

    O inyección de constructor:

    public class ProductBusiness
    {
        private readonly IProductDataAccess _pda;
    
        public ProductBusiness(IProductDataAccess pda)
        {
    
            _pda = pda;
        }
    }
    
    var productBusiness = new ProductBusiness(new ProductDataAccess());
    var productBusiness = new ProductBusiness(new MockProductDataAccess());

    Constructor de la inyección es generalmente la recomiendo enfoque.
    Propiedad de inyección se utiliza para dependencias opcionales (por ejemplo, crear una instancia de un hormigón NullLogger por defecto en el constructor, y el uso de la propiedad de la opción de inyectar un trabajo logger).

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea