I have the following code:
public interface IProductDataAccess
{
bool CreateProduct(Product newProduct);
}
Class ProductDataAccess
implements that interface.
public class ProductBusiness
{
public bool CreateProduct(Product newProduct)
{
IProductDataAccess pda = new ProductDataAccess();
bool result = pda.CreateProduct(newProduct);
return result;
}
}
In this case, how to create unit test for CreateProduct
method by mocking the IProductDataAccess
interface? I thought of having an public instance of IProductDataAccess
within ProductBusiness
and initialize it using Mock<IProductDataAccess>
object but it is not a good practice to expose the data access to the UI layer. Can any one help me?
You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces. However, there are a few limitations you should be aware of. The classes to be mocked can't be static or sealed, and the method being mocked should be marked as virtual.
First, we instantiate the FakeDbArticleMock class and indicate which setup we want to use for this test. Then, it is necessary to instantiate the repository we want to test and inject the mock instance into it. Finally, we call the method we are testing and assert the results.
Classic example which demonstrates that if you cannot unit test a particular component, REFACTOR it!
This is why I love what any mocking framework enforces you to do - write decoupled code.
In your example, the ProductBusiness
class is tightly coupled with the ProductDataAccess
class. You could decouple it using (like most of the answers suggest) dependency injection. By doing so, you would end up depending on the IProductDataAccess
abstraction and not on any concrete implementation of it.
Another point to note, when you are writing tests/specifications for the business layer, you would typically want to test the "behavior" and not the "state". So, although you could have asserts that verify if "true" was returned, your tests should really test if the expected data access calls that were set using MOQ were actually executed using the .Verify
API of MOQ.
Try adding behavior tests where you expect an exception to be thrown (using the ".Throws" API) by the data access layer and check if you need any special handling at the business layer.
Like Kevin suggests, the following implementation of ProductBusiness
will work:
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;
}
}
and use any xunit testing framework to write the test as:
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
You should inject IProductDataAccess
interface as a dependency:
public class ProductBusiness
{
private IProductDataAccess _productDataAccess;
public ProductBusiness(IProductDataAccess productDataAccess)
{
_productDataAccess = productDataAccess;
}
public bool CreateProduct(Product newProduct)
{
bool result = _productDataAccess.CreateProduct(newProduct);
return result;
}
}
Then you can replace it with a mock in your tests:
var productDataAccess = new Mock<IProductDataAccess>();
var productBusiness = new ProductBusiness(productDataAccess.Object);
With the way that you have currently designed your ProductBusiness
class there is no way of changing the IProductDataAccess
implementation using a mock. A recommended pattern for this is dependency-injection where you take the dependencies of a type through the constructor. So your class becomes:
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;
}
}
Now you are in a position to test your class by using a mocking framework like moq. For example:
var mockDataAccess = new Mock<IProductDataAccess>();
mockDataAccess
.Setup(m => m.CreateProduct(It.IsAny<Product>()))
.Returns(true);
var productBusiness = new ProductBusiness(mockDataAccess.Object);
// ... test behaviour here
Now you can change how the mock behaves in your setup step and make sure that your CreateProduct
method is behaving correctly.
I would also look at a dependency injection framework like castle-windsor. A dependency injection framework can automatically resolve dependencies meaning creating a new type is much easier as you don't have to manually new everything up. Also it means that you can change which implementation is used in one place and it changes everywhere.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With