从Ruby世界来之后,我在使用Java进行TDD时遇到的问题很少.最大的问题是当我的应用程序只与外部API通信时.
假设我想从Google日历中获取一些数据,或者从某些Twitter用户获取5条推文并显示它.
在Ruby中,我没有任何问题,因为我可以直接在测试中修补API库,但我在Java中没有这样的选项.
如果我从MVC的角度思考这个问题,我的模型对象就是通过某个库直接访问API.问题是,这是一个糟糕的设计吗?我应该总是在任何接口中包装任何API库,所以我可以用Java模拟/存储它吗?
因为当我想到这个时,那个界面的唯一目的就是模拟(请不要因为这个而杀了我)猴子补丁.这意味着无论何时我使用任何外部资源,我都必须在可以被删除的接口中包装每个层.
# do I have to abstract everything just to do this in Java?
Twitter.stub!(:search)
现在你可能会说我应该总是抽象掉接口,所以我可以将底层更改为其他任何东西.但如果我正在编写Twitter应用程序,我不打算将其更改为RSS阅读器.
是的,我可以添加例如Facebook,然后有接口是有意义的.但是当没有其他资源可以替代我正在使用的资源时,我仍然需要在接口中包装所有内容以使其可测试.
我错过了什么,或者这只是在Java世界中测试的一种方式?
解决方法:
在Java中使用接口通常是很好的做法.有些语言有多重继承,有些语言有鸭子类型,Java有接口.这是该语言的一个关键特性,它让我使用
>不同背景下班级的不同方面
>不改变客户端代码的同一合同的不同实现.
所以接口是一个你应该接受的概念,然后你可以在这样的情况下获得好处,你可以用模拟对象替换你的服务.
关于Java最佳实践的最重要的书之一是Effective Java by Joshua Bloch.我强烈建议你阅读它.在这种情况下,最重要的部分是第52项:通过它们的接口引用对象.引用:
More generally, you should favor the use of interfaces rather than
classes to refer to objects. If appropriate interface types exist, then parameters, return values, variables, and fields should all be declared using interface
types. The only time you really need to refer to an object’s class is when you’re
creating it with a constructor.
如果你更进一步(例如使用依赖注入时),你甚至不会调用构造函数.
切换语言的一个关键问题是你必须改变思维方式.在用语言y思考时,你无法有效地编写语言x.你不能在不使用指针的情况下有效地编写C语言,Ruby不是没有鸭子类型而Java没有使用接口.