【问题标题】:Program to demonstrate TDD + Mocking演示 TDD + Mocking 的程序
【发布时间】:2012-03-11 17:29:25
【问题描述】:

我必须编写一个程序,它接受一个整数并将其转换成英文单词版本。

例如:

Input:  21
Output: twenty one
Input:  110 
Output: one hundred and ten

我需要程序来演示 TDD,所以我想使用模拟。

我编写了一个类,该类具有进行转换的函数(基于 2 个英文单词数组)。我现在需要什么来设计程序,以便我可以使用 Easymock 进行演示。

因此,我需要创建一个接口作为我的模拟对象。谁能给我一些关于如何设计我的程序的建议?

这样合适吗?

  1. 编写一个Converter 类,该类引用一个名为ConverterInterface 的接口。然后我可以模拟界面并将其设置到我的Converter 类中。

欢迎任何帮助。

【问题讨论】:

  • Mocking 通常用于模拟其他东西。你想模拟什么?输出机制?
  • 如果你想演示 TDD,你应该扔掉你的代码,开始写测试。
  • @vaughan:这是我的问题。我的程序可以很容易地在没有模拟的情况下编写,但我需要以一种演示模拟的方式编写它。因此,我需要这样设计它。设计显然会很复杂,但练习是为了演示模拟。
  • 所以基本上,我要问的是可以用这个微不足道的小程序来演示模拟吗?

标签: mocking tdd easymock


【解决方案1】:

您可以在不模拟的情况下演示 TDD。事实上,嘲弄会使刚接触 TDD 的人感到困惑。我会简单地从测试驱动您正在尝试开发的功能开始,然后再担心模拟。假设您已经测试了数字到英语的转换器(根据您的描述,您似乎还没有完成)并且您有一个看起来像这样的类:

public class NumberConverterTest { ... }

public class NumberConverter {
  public String toEnglish(int number) { ... }
}

你可能还有一些主类:

public class NumberConverterMain {
  public void main(String[] args) {
    NumberConverter converter = new NumberConverter();
    System.out.println(converter.toEnglish(args[0]);
  }
}

您现在已经在没有模拟的情况下演示了 TDD。在尝试练习 TDD 时,总是会出现嘲弄的问题。为了演示 mocking,您可以在 toEnglish 方法周围添加一些任意业务规则,例如“所有大于 1000 的数字的请求都必须记录到大数部门”。知道大量部门托管在我们不想依赖的另一台服务器上,我们可以测试驱动接口并模拟它。

public class NumberConverterTest {
  // ..
  @Test public void theLargeNumberDepartmentIsNotifiedForLargeNumbers() {
     LargeNumberDepartment department = new MockLargeNumberDepartment(1000);
     NumberConverter converter = new NumberConverter(department);
     converter.toEnglish(1000);
     assertTrue(department.wasNotifiedWith(1000));
  }

  public static MockLargeNumberDepartment implements LargeNumberDepartment {

     private int valueRequested;

     public void MockLargeNumberDepartment(int threshhold) {
       this.threshold = threshold;
     }

     public int notificationThreshold() {
       return this.threshold;
     }

     public void largeNumberReceived(int value) {
       valueRequested = value;
     }

     public boolean wasNotifiedWith(int value) {
       assertEquals(value, valueRequested);
       return true;
     }
  }
}

// In NumberConverter.java
public class NumberConverter {
  public NumberConverter(LargeNumberDepartment department) {
    this.department = department;
  }

  public String toEnglish(int value) {
    if(value > department.notificationThreshold())
      department.largeNumberReceived(value);
    return convertIt(value);  
  }
}

【讨论】:

  • 感谢所有回复的人。我现在已经在你的帮助下编写了程序。
【解决方案2】:

首先,我同意@Don Roby 的观点,最好的办法是先实际编写测试,然后看看结果是什么,以此作为模拟某事的机会。

我看到这个程序的不同元素。

  1. “主要”可执行部分
  2. 处理命令行参数的逻辑
  3. 将数字转换为单词的算法
  4. 显示输出的机制

前两个可能非常简单。第三个可能足够复杂,可以拥有自己的类。第四个可能很容易打印到控制台,但如果这是一个真正的程序,那么抽象它发送答案的位置可能会有一些价值,这样你就可以插入其他方法,比如写入文件或数据库或其他任何东西,因此并没有完全人为地在那里有一个接口和一个单独运行的具体实现。

【讨论】:

  • 所以你说我应该写一个叫做'ConverterView'的接口,它有一个叫做'display'的抽象方法。然后模拟这个接口并在单元测试中将 System.out 传递给它?那么在实际程序中,显示可以显示到网页上吗?
  • 我已将我的程序拆分如下:带有 main 方法的转换器类。 UserInput 类+接口用于从用户那里获取输入。算法类+接口进行转换。仍然没有找到嘲笑某事的理由......
  • 好吧,如果你正在测试你的 main 方法,你不会测试你的 Algorithm 类和你的 UserInput 类,你只需要确保它们被你期望的调用(使用模拟)然后写算法的单独单元测试和用户输入的单独单元测试。这样,如果 UserInput 有很多问题(格式错误、管道损坏等),您可以将所有这些路径与算法逻辑分开测试,算法逻辑有一组完全不同的可能出错的东西。
【解决方案3】:

模拟通常只有在组件之间有一些职责分工时才有用,其中关注点的分离是通过接口“实现”的。您所说的问题似乎太狭窄而无法说明这一点。一个可行的想法是扩展您的问题,并将数字翻译器设计为多种语言。在这种情况下,我希望出现一种策略模式,其中 INumberTranslator 接口公开一个字符串 Translate(int number) 方法。

您可以相当顺利地从没有模拟的 TDD 过渡到有模拟的 TDD,方法是首先为“翻译成英语”要求编写测试,然后将要求更改为“我们也需要用西班牙语支持这一点”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 2014-12-12
    • 2011-05-30
    相关资源
    最近更新 更多