Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在测试驱动开发中如何避免访问器?_Java_Tdd - Fatal编程技术网

Java 在测试驱动开发中如何避免访问器?

Java 在测试驱动开发中如何避免访问器?,java,tdd,Java,Tdd,我正在学习测试驱动开发,我注意到它强制松散耦合的对象,这基本上是一件好事。然而,这有时也迫使我为我通常不需要的属性提供访问器,我想大多数人都同意,访问器通常是糟糕设计的标志。在进行TDD时,这是不可避免的吗 以下是一个示例,没有TDD的实体的简化图形代码: class Entity { private int x; private int y; private int width; private int height; void draw(Graphi

我正在学习测试驱动开发,我注意到它强制松散耦合的对象,这基本上是一件好事。然而,这有时也迫使我为我通常不需要的属性提供访问器,我想大多数人都同意,访问器通常是糟糕设计的标志。在进行TDD时,这是不可避免的吗

以下是一个示例,没有TDD的实体的简化图形代码:

class Entity {
    private int x;
    private int y;
    private int width;
    private int height;

    void draw(Graphics g) {
        g.drawRect(x, y, width, height);
    }
}
实体知道如何画自己,这很好。都在一个地方。但是,我正在执行TDD,所以我想检查我的实体是否被我将要实现的“fall()”方法正确移动。以下是测试用例的外观:

@Test
public void entityFalls() {
    Entity e = new Entity();
    int previousY = e.getY();
    e.fall();
    assertTrue(previousY < e.getY());
}
松耦合的,好的。我甚至可以将渲染器替换为以完全不同的方式显示实体的渲染器。但是,我必须公开实体的内部状态,即其所有属性的访问器,以便渲染器能够读取它

我觉得这是TDD特别强迫的。我能做些什么?我的设计可以接受吗?java需要C++的“朋友”关键字吗? 更新:

感谢您迄今为止的宝贵投入!然而,我担心我选择了一个不好的例子来说明我的问题。这完全是虚构的,现在我将演示一个更接近我实际代码的代码:

@Test
public void entityFalls() {
    game.tick();
    Entity initialEntity = mockRenderer.currentEntity;
    int numTicks = mockRenderer.gameArea.height
                   - mockRenderer.currentEntity.getHeight();
    for (int i = 0; i < numTicks; i++)
        game.tick();
    assertSame(initialEntity, mockRenderer.currentEntity);
    game.tick();
    assertNotSame(initialEntity, mockRenderer.currentEntity);
    assertEquals(initialEntity.getY() + initialEntity.getHeight(),
                 mockRenderer.gameArea.height);
}
@测试
公共void entityFalls(){
game.tick();
实体initialEntity=mockRenderer.currentEntity;
int numTicks=mockRenderer.gameArea.height
-mockRenderer.currentEntity.getHeight();
对于(int i=0;i
这是一个基于游戏循环的游戏实现,其中一个实体可能会倒下。如果它触地,将创建一个新实体

“mockRenderer”是接口“Renderer”的模拟实现。这种设计部分是由TDD强制的,但也因为我将用GWT编写用户界面,而且浏览器中还没有明确的绘图,所以我认为实体类不可能承担这种责任。此外,我希望将来能够将游戏移植到本机Java/Swing

更新2:


再想一想,也许一切都好。也许可以将实体和图形分开,并且实体告诉其他对象足够的关于自身的信息来绘制。我的意思是,我怎么才能实现这种分离呢?我真的不知道没有它怎么生活。即使是优秀的面向对象程序员有时也会使用带有getter/setter的对象,特别是对于实体对象之类的对象。也许getter/setter并不都是邪恶的。你觉得怎么样?

务实的程序员在讨论。您不想了解实体,而是希望绘制实体。告诉它在给定的图形上绘制自己

您可以重构上面的代码,以便实体绘制图形,如果实体不是矩形而是圆,这将非常有用

void Entity::draw(Graphics g) {
     g.drawRect(x,y, width, height);
} 

然后检查g是否在测试中调用了正确的方法

您要测试的是对象将如何响应某些调用,而不是它内部如何工作

因此,访问不可访问的字段/方法并不是真的必要(这是个坏主意)


如果您想查看方法调用和某个参数之间的交互,您应该模拟所述参数,以便能够测试该方法是否按您希望的方式工作。

因此,如果您没有将
draw(Graphics)
方法从
Entity
移动,您就拥有了完全可测试的代码。您只需将
图形
的实现注入测试线束,该实现报告了
实体
的内部状态。不过,这只是我的看法。

首先,您是否知道
java.awt.Rectangle
类在java运行时库中是如何处理这个问题的

其次,我相信TDD的真正价值首先是它将您的注意力从“我如何使用我假设的数据来处理这个特定细节”转移到“我如何调用代码以及我期望返回什么结果”。传统的方法是“修复细节,然后我们将找出如何调用代码”,如果有什么事情根本无法完成或无法完成,则通过另一种方法可以更快地找到

这在设计API时非常重要,这很可能也是您发现结果是松散耦合的原因


第二个价值是,你的测试是“活的评论”,而不是古老的、未触及的评论。该测试显示了应该如何调用代码,您可以立即验证代码是否按照指定的方式运行。这与您的要求无关,但应该证明测试比盲目调用您前一段时间编写的代码有更多的用途。

您说您觉得您提出的呈现器类是TDD“特别强制”的。那么,让我们看看TDD把你带到了哪里。从一个负责其坐标和绘制自身的矩形类,到一个单独负责维护其坐标的矩形类和一个单独负责渲染矩形的渲染器。这就是我们所说的测试驱动的意思——这种做法会影响您的设计。在这种情况下,它会促使您采用一种更符合设计要求的设计—如果没有测试,您将不会采用这种设计。我认为这是件好事。我认为你很好地实践了TDD,我认为它对你很有用。

我认为你的例子在通信方面有很多好处
void Entity::draw(Graphics g) {
     g.drawRect(x,y, width, height);
}