tldr; Как смоделировать вызов базового метода (используя moq)?
Мне нужно найти способ, чтобы обойти проблему, касающуюся насмешки над методом, который принадлежит класс, от которого я наследую, или чтобы на самом деле иметь возможность просто его высмеивать.
Я начну с публикации некоторого кода:
Код для проверки:
public class CustomProductListingService : ProductListingService
{
public override IEnumerable<Product> ListAllProducts(ICategory category)
{
//does some internal filtering and to the developer unkown magic..
//would like to mock the result of this call..
var baseResult = base.ListAllProducts(category);
if(category.Name.StartsWith("A"))
return baseResult.Where(p => p.Name.StartsWith("A"));
else if(category.Name.StartsWith("B"))
return baseResult.Where(p => p.Name.StartsWith("B"));
else
return baseResult;
}
}
Тест:
[TestMethod]
public void CustomProductListingService_ShouldOnlyReturnProductsWithNameStartingWithA()
{
//arrange
var customProductListingService = new CustomProductListingService();
ICategory category = new category
{
Name = "Abcd"
};
//act
var result = customProductListingService.ListAllProducts(category);
//assert
foreach(var product in result)
{
Assert.IsTrue(product.StartsWith("A"));
}
}
, как вы можете видеть, я вызываю base.ListAllProducts из моей собственной реализации ListAllProducts, теперь я хотел бы смоделировать base.ListAllProducts, так как мне действительно все равно о том, что этот метод делает внутренне и хочет иметь возможность контролировать результат (возврат), чтобы я мог проверить свою собственную реализацию.
Однако есть и другая проблема, этот код является частью реализации для существующая система, где система обычно просто внедряет ProductListingService с использованием DI, но в моем случае мне потребовалось некоторое пользовательское поведение, и именно поэтому существует CustomProductListingService. То, что я в основном сделал, это переопределил регистрацию системы по умолчанию для ProductListingService, и вместо этого сказал ему ввести мой пользовательский класс CustomProductListingService. В этом случае используемой DI-платформой является StructureMap, поэтому в результате регистрация контейнера в результате выглядела бы примерно так:
var container = new Container(c =>
{
//use system implementation
c.For<ProductListingService>().Use<ProductListingService>();
//override system with my implementation
c.For<ProductListingService>().Use<CustomProductListingService>();
});
В этом случае возникает проблема, при которой я не могу просто сделать это:
public class CustomProductListingService : ProductListingService
{
private readonly ProductListingService _productListingService;
public CustomProductListingService(ProductListingService productListingService)
{
this._productListingService = productListingService;
}
public override IEnumerable<Product> ListAllProducts(ICategory category)
{
//does some internal filtering and to the developer unkown magic..
//would like to mock the result of this call..
var baseResult = this._productListingService.ListAllProducts(category);
if(category.Name.StartWith("A"))
return baseResult.Where(p => p.Name.StartWith("A"));
else if(category.Name.StartWith("B"))
return baseResult.Where(p => p.Name.StartWith("B"));
else
return baseResult;
}
}
Так как это вызвало бы круговую зависимость и было бы странно вводить экземпляр того же типа, что и класс, от которого я наследую. (Если бы это было возможно, я мог бы просто посмеяться над экземпляром, переданным конструктору в качестве параметра).
Есть идеи, как это обойти? Вероятно, следует добавить, что mocking-framework, который я использую, это Moq, если это как-то облегчает решение.