-1

我正在关注一个较早的 Java 教程,该教程正在教授服务层的概念,我的程序是一个非常简单的程序,它将创建一个账单列表及其到期日。我陷入困境的是为工厂方法创建 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 测试,该测试应使用工厂获取服务,在 setUp() 方法中实例化。

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

任何帮助表示赞赏。谢谢

4

3 回答 3

3

首先,不要扩展TestCase- 而是使用 JUnit 4.x。

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

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

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

同样的事情适用于read- 当我尝试阅读账单时,我期望收到什么输入?我从传入一个Bill对象并返回一个Bill对象中得到什么?(为什么外部来电者会有我正在尝试阅读的账单的概念?)

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

  • 给定一个特定的输入,
  • 我调用这个方法时,
  • 那么我希望这些事情是真实的。

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

于 2013-07-21T08:21:14.007 回答
1

IMOsave方法应该返回一些东西来说明是否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));
}
于 2013-07-21T07:54:04.720 回答
0

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

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

    bill.store(aBill);

    //fetch the inserted bill then assert
}

这些测试的重点是您的组件是否对外部系统进行了正确的抽象。

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

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
}
于 2013-07-21T12:28:30.497 回答