编写/实现API:可测试性与信息隐藏 [英] Writing/implementing an API: testability vs information hiding

查看:90
本文介绍了编写/实现API:可测试性与信息隐藏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很多时候我都在API的设计/实现中遇到这个难题.

Many times I am involved in the design/implementation of APIs I am facing this dilemma.

我是信息隐藏的坚定支持者,并尝试使用各种技术来实现这一目标,包括但不限于内部类,私有方法,程序包私有限定符等.

I am a very strong supporter of information hiding and try to use various techniques for that, including but not limited to inner classes, private methods, package-private qualifiers, etc.

这些技术的问题在于它们倾向于阻止良好的可测试性.尽管其中一些技术可以解决(例如,通过将一个类放入相同的程序包来实现程序包私有性),但其他一些技术

The problem with these techniques is that they tend to prevent good testability. And while some of these techniques can be resolved (e.g. package-privateness by putting a class into the same package), others are not so easy to tackle and either requires reflection magic or other tricks.

让我们看一下具体示例:

Let's look at concrete example:

public class Foo {
   SomeType attr1;
   SomeType attr2;
   SomeType attr3;

   public void someMethod() {
      // calculate x, y and z
      SomethingThatExpectsMyInterface something = ...;
      something.submit(new InnerFoo(x, y, z));
   }

   private class InnerFoo implements MyInterface {
      private final SomeType arg1;
      private final SomeType arg2;
      private final SomeType arg3;

      InnerFoo(SomeType arg1, SomeType arg2, SomeType arg3) {
         this.arg1 = arg1;
         this.arg2 = arg2;
         this.arg3 = arg3;
      }

      @Override
      private void methodOfMyInterface() {
         //has access to attr1, attr2, attr3, arg1, arg2, arg3
      }
   }
}

有很强的理由不公开InnerFoo-没有其他类,图书馆应该可以访问它,因为它没有定义任何公共合同,并且作者故意不希望它可以访问.但是,要使其成为100%TDD原始且可无任何反射技巧地访问,应按以下方式重构InnerFoo:

There are strong reasons not to expose InnerFoo - no other class, library should have access to it as it does not define any public contract and the author deliberately didn't want it to be accessible. However to make it 100% TDD-kosher and accessible without any reflection tricks, InnerFoo should be refactored like this:

private class OuterFoo implements MyInterface {
   private final SomeType arg1;
   private final SomeType arg2;
   private final SomeType arg3;
   private final SomeType attr1;
   private final SomeType attr2;
   private final SomeType attr3;

   OuterFoo(SomeType arg1, SomeType arg2, SomeType arg3, SomeType attr1, SomeType attr2, SomeType attr3) {
      this.arg1 = arg1;
      this.arg2 = arg2;
      this.arg3 = arg3;
      this.attr1 = attr1;
      this.attr2 = attr2;
      this.attr3 = attr3;
   }

   @Override
   private void methodOfMyInterface() {
      //can be unit tested without reflection magic
   }
}

此示例仅涉及3个attrs,但是具有5-6是相当合理的,然后OuterFoo构造函数将必须接受8-10个参数!在顶部添加getter,您已经有100行完全无用的代码(也需要getter来获取这些attrs进行测试).是的,我可以通过提供一种构建器模式来使情况更好一些,但是我认为这不仅过度设计,而且还违反了TDD本身的目的!

This examply only involves 3 attrs, but it is pretty reasonable to have 5-6 and the OuterFoo constructor would then have to accept 8-10 parameters! Add getters on top, and you already have 100 lines of completely useless code (getters would be also required to get these attrs for testing). Yes, I could make the situation a bit better by providing a builder pattern but I think this is not only over-engineering but also defeats the purpose of TDD itself!

解决此问题的另一种方法是公开类Foo的受保护方法,在FooTest中扩展它并获取所需的数据.再次,我认为这也是一种不好的方法,因为protected方法确实定义了合同,并且通过公开该合同,我现在已经对其进行隐式签名.

Another solution for this problem would be to expose a protected method for class Foo, extend it in FooTest and get the required data. Again, I think this is also a bad approach because protected method does define a contract and by exposing it I have now implicitly signed it.

别误会我的意思. 我喜欢编写可测试的代码. 我喜欢简洁,简洁的API,短代码块,可读性等.但是我不喜欢的是在信息隐藏方面做出了任何牺牲,只是因为它更容易进行单元测试 .

Don't get me wrong. I like to write testable code. I love concise, clean APIs, short code blocks, readability, etc. But what I don't like is making any sacrifices when it comes to information hiding just because it is easier to unit test.

有人能对此提出任何想法吗(总体而言,特别是特别如此)?对于给定的示例,还有其他更好的解决方案吗?

Can anybody provide any thoughts on this (in general, and in particular)? Are there any other, better solutions for given example?

推荐答案

我认为您应该重新考虑使用反射.

I think you should reconsider using reflection.

它有其缺点,但是如果它允许您在没有虚拟代码的情况下维护所需的安全模型,那可能是一件好事.反射通常不是必需的,但有时没有很好的替代品.

It has its own downsides but if it allows you to maintain the security model you want without dummy code, that may be a good thing. Reflection is often not required, but sometimes there is no good substitute.

另一种隐藏信息的方法是将类/对象视为黑匣子,并且不访问任何非公共方法(尽管这样做可以使测试通过错误"原因,即答案正确但错误)原因.)

Another approach to information hiding is to treat the class/object as a black box and not access any non-public methods (Though this can allow tests to pass for the "wrong" reasons i.e. the answer is right but for the wrong reasons.)

这篇关于编写/实现API:可测试性与信息隐藏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆