为工厂方法创建单元测试

时间:2013-07-21 07:49:51

标签: java junit

我正在学习一个教授服务层概念的旧Java教程,我的程序是一个非常简单的程序,它将创建一个Bills列表及其截止日期。我遇到的问题是为工厂方法创建JUnit测试。

首先是Bill Constructor

public Bill(String bname, Double bamount, Date bdate, String bfrequency){
 this.billName = bname;
 this.billAmount = bamount;
 this.billDueDate = bdate;
 this.frequency = bfrequency;
}

接下来是保存和获取这些账单的界面

public interface IBill {
    public void save(Bill bill);
    public Bill read(Bill readbill);


}

请耐心等待,接下来是接口的具体实现,暂时已经删除,尚未实现

public class BillSvcImpl implements IBill {

    @Override
    public void save(Bill bill) {
        System.out.println("Entering the Store BillInfo method");

    }

    @Override
    public Bill read(Bill readbill) {
        System.out.println("Entering the Read BillInfo method");
        return null;
    }

}

然后有工厂方法将创建/调用具体实现

public class Factory {

    public IBill getBillInfo(){
        return new BillSvcImpl();
    }

}

然后最后JUnit测试了我被困的地方

    public class BillSvcTest extends TestCase {
    private Factory factory;

    @Before
    public void setUp() throws Exception {
        super.setUp();
        factory = new Factory();

    }
    @test
    public void testSaveBill(){
        IBill bill = factory.getBillInfo();
        Bill nanny = new Bill("Nanny",128d,new Date(6/28/2013),"Montly");
        bill.save(nanny);
        //what goes here??, Assert??

    }

    @test
    public void testReadBill(){
    //How can I write a Test for this??
        //Please help
    }

}

指令是

  
    

为您的服务创建一个JUnit测试,测试应该使用Factory来获取服务,在setUp()方法中实例化。

  

我的服务/接口有两种方法save和get,在开始实际实现之前,如何为这些创建测试。

感谢任何帮助。 谢谢

3 个答案:

答案 0 :(得分:3)

首先,don't extend TestCase - 而是使用JUnit 4.x。

其次,我对一种有副作用的方法感到非常不满。我们没有理由修改您的save方法以返回boolean而不是void;你只需要采用另一种方法来测试方法。

第三,我认为简单的单元测试无法涵盖此方法的保存功能。读起来的东西会在某个地方持久存在,更适合某种集成测试(使用数据库,确保文件存在且内容正确等)。

单元测试时要回答的主要问题是“给定此参数时此方法调用的预期结果是什么?”当我们致电save时,我们会发生什么?我们写信给数据库吗?我们是否序列化内容并写入文件?我们写XML / JSON /纯文本了吗?首先必须回答这个问题,然后可以围绕它编写一个有用的测试。

同样适用于read - 当我尝试阅读账单时,我期望收到什么作为输入?传入Bill对象并返回Bill对象可以获得什么? (为什么外面的来电者会想到我想读的账单?)

你必须充实你对这些方法的期望。这是我用来编写单元测试的方法:

  • 给定特定输入
  • 何时我称之为此方法,
  • 然后我希望这些事情都是真的。

在编写单元测试之前,您必须定义您的期望

答案 1 :(得分:1)

IMO save方法应该返回一些内容,说明Bill是否已保存。我会像这样保存方法

public boolean save(Bill bill) {
    System.out.println("Entering the Store BillInfo method");
    boolean result = false;
    try {
       //..... saving logic
       result = true;
    }
    catch(Exception e) {
        result = false;
        e.printStackTrace();
    }
    return result;
}

并在测试用例中做了一个断言

@Test
public void testSaveBill(){
    //Success
    IBill bill = factory.getBillInfo();
    Bill nanny = new Bill("Nanny",128d,new Date(6/28/2013),"Montly");
    assertTrue(bill.save(nanny));

   //Failure
   assertFalse(bill.save(null));
}

答案 2 :(得分:0)

通常,read()和store()的实现涉及与外部系统(如数据库,文件系统)的集成。这使得测试与外部系统齐头并进。

@Test
public void insertsBillToDatabase() {
    //setup your database

    bill.store(aBill);

    //fetch the inserted bill then assert
}

这些测试主要关注您的组件是否在外部系统上进行正确的abstration。

依赖于外部系统的测试很昂贵,因为它们相对较慢且难以设置/清理。如果商店()中存在一些复杂的业务逻辑,您最好将业务包含和集成问题分开。

public void store(Bill bill) {
    //business logic
    billDao.save(bill); // delegate to an injected dao, you can replace it with a test double in test code
}

@Test
public void doesSthToBillBeforeSave() {
    //replace your billDao with a stub or mock

    bill.store(aBill);

    //assert the billDao stub / mock are correctly invoked
    //assert bill's state
}