我有时使用FizzBuzz向新手演示单元测试的基础。 尽管FizzBuzz确实是一个简单的问题,但是它也可以用于演示更高级的单元测试技术,例如模拟 。
FizzBuzz Kata:
“ 编写一个程序,打印从1到100的数字。但是,对于三个数字的倍数,请打印“ Fizz”,而不是数字;对于五个数字的倍数,请打印“ Buzz”。 对于三和五的倍数的数字,请打印“ FizzBuzz ”。
FizzBuzz算法的可能解决方案:
public class FizzBuzz {private static final int FIVE = 5;private static final int THREE = 3;public String calculate(int number) {if (isDivisibleBy(number, THREE) && isDivisibleBy(number, FIVE)) {return "FizzBuzz";}if (isDivisibleBy(number, THREE)) {return "Fizz";}if (isDivisibleBy(number, FIVE)) {return "Buzz";}return "" + number;}private boolean isDivisibleBy(int dividend, int divisor) {return dividend % divisor == 0;}
}
由于上面的代码解决了FizzBuzz算法,因此无法解决FizzBuzz问题。 要完成它,我们需要使用该算法的代码来打印从1到100的数字。 代码的这一部分可以用来展示在JUnit中使用Mockito进行模拟的想法。
作为此练习的结果,我最终得到了一个NumberPrinter
,它带有两个参数: Printer
和NumberCalculator
并且具有一个公共方法来打印数字:
public class NumberPrinter {private NumberCalculator numberCalculator;private Printer printer;public NumberPrinter(NumberCalculator numberCalculator, Printer printer) {this.numberCalculator = numberCalculator;this.printer = printer;}public void printNumbers(int limit) {if (limit < 1) {throw new RuntimeException("limit must be >= 1");}for (int i = 1; i <= limit; i++) {try {printer.print(numberCalculator.calculate(i));} catch (Exception e) {// noop}}}
}public interface NumberCalculator {String calculate(int number);
}public interface Printer {void print(String s);
}
引入接口后,我不仅拥有可测试的代码,而且拥有更强大的代码。 为了测试NumberPrinter
我只是使用Mockito的强大功能和简单性来模拟依赖项。 使用Mockito批注,配置测试代码的读取效果更好。
Mockito功能展示:
- 创建和注入模拟
- 存根方法还可以为连续的方法调用设置不同的行为。
- 将void方法存入一个异常
- 验证
使用的注释:
-
@RunWith(MockitoJUnitRunner.class)
–在每个测试方法之前初始化@Mock
-
@Mock
–将字段标记为模拟 -
@InjectMocks
–标记应在其上执行注射的字段
@RunWith(MockitoJUnitRunner.class)
public class NumberPrinterTest {@Mockprivate Printer printer;@Mockprivate NumberCalculator numberCalculator;@InjectMocksprivate NumberPrinter numberPrinter;@Testpublic void printsCalculatorResultsHundredTimes() {// arrangeint limit = 100;when(numberCalculator.calculate(anyInt())).thenReturn("0") // first invocation returns "0".thenReturn("1"); // other invocations return "1"// actnumberPrinter.printNumbers(limit);// assertverify(numberCalculator, times(limit)).calculate(anyInt());verify(printer, times(1)).print("0");verify(printer, times(limit - 1)).print("1");verifyNoMoreInteractions(numberCalculator, printer);}@Testpublic void continuesOnCalculatorOrPrinterError() {// arrangewhen(numberCalculator.calculate(anyInt())).thenReturn("1").thenThrow(new RuntimeException()).thenReturn("3");// stub the void method with an exceptiondoThrow(new RuntimeException()).when(printer).print("3");// actnumberPrinter.printNumbers(3);// assertverify(numberCalculator, times(3)).calculate(anyInt());verify(printer).print("1");verify(printer).print("3");verifyNoMoreInteractions(numberCalculator, printer);}
}
享受Mockito !
- 想更多地了解Mockito注释? 看看Eugen Paraschiv的“ Mockito – @ Mock,@ Spy,@ Captor和@InjectMocks”: http : //www.baeldung.com/mockito-annotations
- 寻找代码样本? 看一下介绍单元测试不同方面的unit-testing-demo项目,包括模拟: https : //github.com/kolorobot/unit-testing-demo
翻译自: https://www.javacodegeeks.com/2014/11/unit-testing-exercise-with-fizzbuzz-and-mockito.html