新Java应用程序的TDD - 我应该从哪里开始?

时间:2012-10-05 12:34:04

标签: tdd

目标:在典型的企业Java环境中测试TDD。

背景:

使用的框架(即使它过度杀伤,我练习project based learning):

  • DAO:Hibernate
  • Spring IoC
  • Front:Spring MVC + Twitter Boostrap(如果可能)
  • TDD:JUnit
  • DB:PostgreSQL

我的项目是一个简单的结算系统,可以帮助自由职业者创建,编辑和打印/向客户发送账单。

创建和配置项目后,我不知道从哪里开始。 假设我的第一个功能是创建一个具有唯一编号和标题的帐单。

问题:我应该先测试什么?

  • 带有createBill(String title)方法的Domain层,它会生成一个唯一的序列号?我会嘲笑数据库层。
  • 首先是用户界面,嘲笑服务层?我不知道怎么做。

提前感谢您的回答,

干杯

1 个答案:

答案 0 :(得分:4)

从测试开始: - )

你的系统做了什么?

public class BillingSystemTest {
    @Test
    public void generatesBills() {
        Bill bill = new BillingSystem().generate()
        assertNotNull(bill)
    }
}

首次测试完成!

让它通过,继续下一个测试...

@Test
public void generatesAnInvoiceNumberForEachBill() {
    Bill bill = new BillingSystem().generate()
    assertEquals(1, bill.getNumber())
}

// ...and the next
@Test
public void generatesUniqueInvoiceNumbersForEachBill() {
    BillingSystem bs = new BillingSystem()
    assertEquals(1, bs.generate().getNumber())
    assertEquals(2, bs.generate().getNumber())
}

@Test
public void generatesAnInvoiceSubjectWhenNoneIsSpecified() {
    Bill bill = new BillingSystem().generate()
    assertEquals("Invoice #1 from ACME Corp.", bill.getSubject())
}

@Test
public void allowsForCustomSubjectsOnBills() {
    Bill bill = new BillingSystem().generate("Custom subject")
    assertEquals("Custom subject", bill.getSubject())
}

我显然已经跳过了重构步骤,但是现在您已经完成了测试以及随之而来的代码,您需要对其进行评估以获得更多机会。我想象代码看起来像这样。

public class BillingSystem {
    private nextInvoiceNumber = 1;

    public Bill generate() {
        return generate("Invoice #" + nextInvoiceNumber + " from ACME Corp.");
    }

    public Bill generate(String subject) {
        Bill bill = new Bill(nextInvoiceNumber, subject)
        nextInvoiceNumber++
        return bill;
    }
}

查看此代码,似乎没问题,但可能违反单一责任原则(SRP)。这里BillingSystem生成账单以及管理发票编号。这是重构的机会。重构后,您的设计可能如下所示:

public class BillingSystem {
    private InvoiceNumbering invoiceNumbering = new InvoiceNumbering()

    public Bill generate() {
        return generate("Invoice #" + invoiceNumbering.peekNext() + " from ACME Corp.");
    }

    public Bill generate(String subject) {
        Bill bill = new Bill(invoiceNumbering.generateNext(), subject)
        nextInvoiceNumber++
        return bill;
    }
}

您的设计更好,您的测试全部通过。接下来要做的是重构测试以从中删除实现细节。他们最终可能会看起来像:

@Test
public void generatesBills() {
    Bill bill = new BillingSystem().generate()
    assertNotNull(bill)
}

@Test
public void generatesAnInvoiceNumberForEachBill() {
    // Using hand rolled mocks
    MockInvoiceNumbering in = new MockInvoiceNumbering()
    in.generateNextShouldReturn(4)

    Bill bill = new BillingSystem(in).generate()
    assertEquals(4, bill.getNumber())
}

@Test
public void generatesUniqueInvoiceNumbersForEachBill() {
    MockInvoiceNumbering in = new MockInvoiceNumbering()

    BillingSystem bs = new BillingSystem(in)

    bs.generate();
    bs.generate();

    assertEquals(2, in.numberOfTimesGenerateNextWasCalled)
}

@Test
public void generatesAnInvoiceSubjectWhenNoneIsSpecified() {
    Bill bill = new BillingSystem().generate()
    assertEquals("Invoice #1 from ACME Corp.", bill.getSubject())
}

@Test
public void allowsForCustomSubjectsOnBills() {
    Bill bill = new BillingSystem().generate("Custom subject")
    assertEquals("Custom subject", bill.getSubject())
}

作为此重构的一部分,您可能会围绕InvoiceNumbering类创建一些测试。

希望这是一个开始。留下了很多。 : - )

希望有所帮助!

布兰登