Joh*_*now 1 c# java unit-testing design-patterns dependency-injection
我一直在阅读如何编写可测试代码,并偶然发现了依赖注入设计模式。
这种设计模式非常容易理解,而且实际上没有什么意义,对象请求值而不是自己创建它们。
然而,现在我正在考虑如何将其用于我当前正在开发的应用程序,我意识到它存在一些复杂性。想象一下下面的例子:
public class A{
public string getValue(){
return "abc";
}
}
public class B{
private A a;
public B(A a){
this.a=a;
}
public void someMethod(){
String str = a.getValue();
}
}
Run Code Online (Sandbox Code Playgroud)
单元测试someMethod ()现在会很容易,因为我可以创建 A 的模拟并返回getValue()我想要的任何内容。
类 B 对 A 的依赖是通过构造函数注入的,但这意味着 A 必须在类 B 之外实例化,因此此依赖项已移至另一个类。这将重复很多层,并且在某些点上必须完成实例化。
现在的问题是,使用依赖注入时,您是否会不断通过所有这些层传递依赖项?这是否会降低代码的可读性并增加调试时间?当您到达“顶层”时,您将如何对该类进行单元测试?
我希望我正确理解你的问题。
注入依赖项
不,我们不会将依赖关系传递到所有层。我们只将它们传递给直接与它们对话的层。例如:
public class PaymentHandler {
private customerRepository;
public PaymentHandler(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public void handlePayment(CustomerId customerId, Money amount) {
Customer customer = customerRepository.findById(customerId);
customer.charge(amount);
}
}
public interface CustomerRepository {
public Customer findById(CustomerId customerId);
}
public class DefaultCustomerRepository implements CustomerRepository {
private Database database;
public CustomerRepository(Database database) {
this.database = database;
}
public Customer findById(CustomerId customerId) {
Result result = database.executeQuery(...);
// do some logic here
return customer;
}
}
public interface Database {
public Result executeQuery(Query query);
}
Run Code Online (Sandbox Code Playgroud)
PaymentHandler不知道Database,它只谈论CustomerRepository。注入Database在存储库层停止。
代码的可读性
当在没有框架或库帮助的情况下进行手动注入时,我们最终可能会得到包含许多样板代码的工厂类,return new D(new C(new B(), new A());这些代码在某些时候可能可读性较差。为了解决这个问题,我们倾向于使用像Guice这样的 DI 框架来避免编写这么多工厂。
然而,对于实际执行工作/业务逻辑的类,它们应该更具可读性和可理解性,因为它们只与直接协作者交谈并完成他们需要做的工作。
单元测试
我假设“顶层”是指类PaymentHandler。在此示例中,我们可以创建一个存根CustomerRepository类并让它返回一个Customer我们可以检查的对象,然后将存根传递给 来PaymentHandler检查是否收取了正确的金额。
总体思路是传入假协作者来控制他们的输出,以便我们可以安全地断言被测类(在本例中为类PaymentHandler)的行为。
为什么需要接口
正如上面的评论中提到的,最好依赖接口而不是具体的类,它们提供更好的可测试性(易于模拟/存根)和更容易的调试。
希望这可以帮助。