程序模块化 与 单元测试
不知道同学们有没有过这样的困惑,程序写着写着,就奇长无比,回头看,已经不知道这段代码为何物,百般思索过后终于想起来,但又忘记了当前代码写到了哪里。如果你也有此困惑,那么就请用一点时间读读下面的话。
这是一个简单的四则运算java程序:
import java.util.*;
public class CalcExample2{
public static void main(String args[]){
ArrayList<String> al=new ArrayList<String>();
System.out.println("请输入要计算的式子个数:");
Scanner sc=new Scanner(System.in);
int count=sc.nextInt();
System.out.println("请输入你要求解的式子:");
for(int i=0;i<count;i++){
sc=new Scanner(System.in);
al.add(sc.nextLine());
}
for(int i=0;i<count;i++){
System.out.print(al.get(i)+"=");
//f(al.get(i));
if(al.get(i).indexOf("+")>-1){
String[] str=al.get(i).split("[+]");
System.out.println(Integer.parseInt(str[0])+Integer.parseInt(str[1]));
}else if(al.get(i).indexOf("-")>-1){
String[] str=al.get(i).split("[-]");
System.out.println(Integer.parseInt(str[0])-Integer.parseInt(str[1]));
}else if(al.get(i).indexOf("*")>-1){
String[] str=al.get(i).split("[*]");
System.out.println(Integer.parseInt(str[0])*Integer.parseInt(str[1]));
}else if(al.get(i).indexOf("/")>-1){
String[] str=al.get(i).split("[/]");
System.out.println(Integer.parseInt(str[0])/Integer.parseInt(str[1]));
}else if(al.get(i).indexOf("%")>-1){
String[] str=al.get(i).split("[%]");
System.out.println(Integer.parseInt(str[0])%Integer.parseInt(str[1]));
}
}
}
}
可能有点简单哈,但是你有没有考虑过,如果这个程序的难度系数增加了呢?如果需要你写个计算不只有两个运算数字的四则运算呢?如果需要你写个带图形化界面的四则运算呢?就目前上边这个这么简单的程序,我就已经一屏看不完了,那么这个程序如果再发展状大,你看了好几屏之后,还记得之前看了什么吗?
这个程序的缺点就在于所有的代码都写在一个main
方法里了,如果程序持续增长,会导致代码越来越多,以致程序到最后可能会牵一发而动全身,比如在上面的程序中,我修改了al
的名字,那么这个程序中所有的al
都需要修改,如果少修改了一处,程序就会错误。那么如何让程序看起来简单易懂呢?那么有一个非常不错的方法,就是一个程序只干一件事,也可以说是模块化
。比如在我们上面这个程序中,我们可以将运算
部分提取出来,让这个运算的部分单独成为一个模块,那么当以后修改这个运算模块的时候就不会“动全身”啦。
import java.util.*;
public class CalcExample{
public static void main(String args[]){
ArrayList<String> al=new ArrayList<String>();
System.out.println("请输入要计算的式子个数:");
Scanner sc=new Scanner(System.in);
int count=sc.nextInt();
System.out.println("请输入你要求解的式子:");
for(int i=0;i<count;i++){
sc=new Scanner(System.in);
al.add(sc.nextLine());
}
for(int i=0;i<count;i++){
System.out.print(al.get(i)+"=");
calc(al.get(i));
}
}
public static void calc(String s){
if(s.indexOf("+")>-1){
String[] str=s.split("[+]");
System.out.println(Integer.parseInt(str[0])+Integer.parseInt(str[1]));
}else if(s.indexOf("-")>-1){
String[] str=s.split("[-]");
System.out.println(Integer.parseInt(str[0])-Integer.parseInt(str[1]));
}else if(s.indexOf("*")>-1){
String[] str=s.split("[*]");
System.out.println(Integer.parseInt(str[0])*Integer.parseInt(str[1]));
}else if(s.indexOf("/")>-1){
String[] str=s.split("[/]");
System.out.println(Integer.parseInt(str[0])/Integer.parseInt(str[1]));
}else if(s.indexOf("%")>-1){
String[] str=s.split("[%]");
System.out.println(Integer.parseInt(str[0])%Integer.parseInt(str[1]));
}
}
}
这样,计算的部分就从程序中脱离出来了。那么计算的部分从主函数中脱离出来了,但是这个程序依然会存在随着代码增多,屏数越来越多的问题,可能我们看完一个模块就找不到原来阅读的程序的位置了。我们希望一个程序只做一件事
,这样就可以实现每一个程序的反复利用。那么我们将计算部分自立门户,使它成为一个类中的方法。
CalcExample.java
import java.util.*;
public class CalcExample{
public static void main(String args[]){
ArrayList<String> al=new ArrayList<String>();
System.out.println("请输入要计算的式子个数:");
Scanner sc=new Scanner(System.in);
int count=sc.nextInt();
System.out.println("请输入你要求解的式子:");
for(int i=0;i<count;i++){
sc=new Scanner(System.in);
al.add(sc.nextLine());
}
for(int i=0;i<count;i++){
System.out.print(al.get(i)+"=");
Calc calc = new Calc();;
calc.calc(al.get(i));
}
}
}
Calc.java
public class Calc {
private int result;
public void calc(String s){
if(s.indexOf("+")>-1){
add(s);
}else if(s.indexOf("-")>-1){
substract(s);
}else if(s.indexOf("*")>-1){
multiply(s);
}else if(s.indexOf("/")>-1){
divide(s);
}else if(s.indexOf("%")>-1){
remainder(s);
}
System.out.println(getResult());
}
public void add(String s)
{
String[] str=s.split("[+]");
result =Integer.parseInt(str[0])+Integer.parseInt(str[1]);
}
public void substract(String s)
{
String[] str=s.split("[-]");
result = Integer.parseInt(str[0])-Integer.parseInt(str[1]);
}
public void multiply(String s)
{
String[] str=s.split("[*]");
result = Integer.parseInt(str[0])*Integer.parseInt(str[1]);
}
public void divide(String s)
{
String[] str=s.split("[/]");
result = Integer.parseInt(str[0])/Integer.parseInt(str[1]);
}
public void remainder(String s)
{
String[] str=s.split("[%]");
result = Integer.parseInt(str[0])%Integer.parseInt(str[1]);
}
public int getResult()
{
return result;
}
}
这样,通过calc.calc(al.get(i));
任何程序想使用这段计算的代码都可以使用了。而且还方便我们测试用,在保证main
函数完全没有问题的时候,如果计算结果发生了错误,我们就可以只测试Calc一个类。
那么如何测试一个类到底对不对呢?我使用了eclipse下的junit来测试, junit的安装方法。以下是我的Junit的测试用例:
CalcTest.java
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class CalcTest {
Calc calc = new Calc();
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testCalc() {
fail("Not yet implemented");
}
@Test
public void testAdd() {
calc.add("2+3");
assertEquals(5, calc.getResult());
}
@Test
public void testSubstract() {
calc.add("2");
assertEquals(5, calc.getResult());
}
@Test
public void testMultiply() {
//啥也没写
}
@Test
public void testDivide() {
//啥也没写
}
@Test
public void testRemainder() {
//啥也没写
}
}
程序的结果就是下面的样子啦:
我只有加法的结果给的是正确的,别的要不就没写,要不就不对,junit都告诉我了。
有了这个结果,我们就可以测试任意一个模块啦~