简体   繁体   中英

Is it a Test Driven Development approach?

Suppose the following model

public class Product {

    private Integer requiredQuantity;
    private Integer allowedQuantity;

    // getters and setters

} 

public class Order {

    public void allowsOrder(List<Product> productList) throws AppException {

        Integer allowedQuantity = 0;
        Integer requiredQuantity = 0;
        for(Product product: productList) {
            if(product.getAllowedQuantity().compareTo().product.getRequiredQuantity() > 0)
                throw new AllowedQuantityIsGreaterThanRequiredQuantity();

                allowedQuantity += product.getAllowedQuantity();
                requiredQuantity += product.getRequiredQuantity();                          
        }

        switch(allowedQuantity.compareTo(requiredQuantity)) {
            case 0:
                setOrderStatus(OrderStatus.ALLOWED);
            break;
            case -1:
                if(allowedQuantity.equals(0))
                    setOrderStatus(OrderStatus.DENIED);
                else
                    setOrderStatus(OrderStatus.PARTIALLY_ALLOWED);
            break;
        }
    }
}

So i have developed (BEFORE code above) a Test Driven Development according to:

obs: for each test method a dataProvider (by using TestNG) supplies parameters

public void successAllowedOrder(List<Product> productList, Order beforeAllowingOrderMock, Order afterAllowingOrderMock) {
    Integer allowedQuantity = 0;
    Integer requiredQuantity = 0;
    for(Product product: productList) {
        allowedQuantity += product.getAllowedQuantity();
        requiredQuantity += product.getRequiredQuantity();
    }

    assertEquals(allowedQuantity, requiredQuantity);

    assertNull(beforeAllowingOrderMock.getOrderStatus());
    assertEquals(OrderStatus.ALLOWED, afterAllowingOrderMock.getOrderStatus());

    // beforeAllowingOrderMock is now a implementation
    beforeAllowingOrderMock = new Order();

    beforeAllowingOrderMock.allowsOrder(productList);

    assertNotNull(beforeAllowingOrderMock.getOrderStatus());
    assertEquals(beforeAllowingOrderMock.getOrderStatus(), afterAllowingOrderMock.getOrderStatus());
}

public void successPartiallyAllowedOrder(List<Product> productList, Order beforeAllowingOrderMock, Order afterAllowingOrderMock) {
    Integer allowedQuantity = 0;
    Integer requiredQuantity = 0;
    for(Product product: productList) {
        allowedQuantity += product.getAllowedQuantity();
        requiredQuantity += product.getRequiredQuantity();
    }

    assertTrue(requiredQuantity > allowedQuantity);

    assertNull(beforeAllowingOrderMock.getOrderStatus());
    assertEquals(OrderStatus.PARTIALLY_ALLOWED, afterAllowingOrderMock.getOrderStatus());

    // beforeAllowingOrderMock is now a implementation
    beforeAllowingOrderMock = new Order();

    beforeAllowingOrderMock.allowsOrder(productList);

    assertNotNull(beforeAllowingOrderMock.getOrderStatus());
    assertEquals(beforeAllowingOrderMock.getOrderStatus(), afterAllowingOrderMock.getOrderStatus());
}

public void successDeniedOrder(List<Product> productList, Order beforeAllowingOrderMock, Order afterAllowingOrderMock) {
    Integer allowedQuantity = 0;
    Integer requiredQuantity = 0;
    for(Product product: productList) {
        allowedQuantity += product.getAllowedQuantity();
        requiredQuantity += product.getRequiredQuantity();
    }

    assertTrue(allowedQuantity == 0);

    assertNull(beforeAllowingOrderMock.getOrderStatus());
    assertEquals(OrderStatus.DENIED, afterAllowingOrderMock.getOrderStatus());

    // beforeAllowingOrderMock is now a implementation
    beforeAllowingOrderMock = new Order();

    beforeAllowingOrderMock.allowsOrder(productList);

    assertNotNull(beforeAllowingOrderMock.getOrderStatus());
    assertEquals(beforeAllowingOrderMock.getOrderStatus(), afterAllowingOrderMock.getOrderStatus());
}

public void failureAllowedQuantityIsGreaterThanRequiredQuantity(List<Product> productList, Order beforeAllowingOrderMock) {
    Integer allowedQuantity = 0;
    Integer requiredQuantity = 0;
    for(Product product: productList) {
        allowedQuantity += product.getAllowedQuantity();
        requiredQuantity += product.getRequiredQuantity();
    }

    assertTrue(allowedQuantity > requiredQuantity);

    try {
        beforeAllowingOrderMock.allowsOrder(productList);
    } catch(Exception e) {
        assertTrue(e instanceof AllowedQuantityIsGreaterThanRequiredQuantity);
    }

    // beforeAllowingOrderMock is now a implementation
    beforeAllowingOrderMock = new Order();

    try {
        beforeAllowingOrderMock.allowsOrder(productList);
    } catch(Exception e) {
        assertTrue(e instanceof AllowedQuantityIsGreaterThanRequiredQuantity);
    }
}

If i have developed failure case first and for each test method a mock and, after mock, a implementation, is it a Test Driven Development approach ?

regards,

While there may be other conditions that people place on it, generally if you're writing tests before and as you code, it is probably test driven. You usually come up with tests that fail at first, and then you write code to make them pass.

As long as there are tests, you can't look at the code and see if it was developed using TDD or not. The TDD cycle looks like this:

  1. write test.
  2. make it pass.
  3. refactor.

One subtle thing is that you may not add any new functionality unless it is to make a failing test pass.

The number of mocks used is irrelevant.

Who is invoking the method such as successAllowedOrder(), successPartiallyAllowedOrder(), successDeniedOrder() ? I'm asking cause TestCases usually do not have parameters.

Typically unit-tests written applying TDD follow a triple A pattern :

  • A rrange
  • A ct
  • A ssert

There also are fixtures, the environment where the test will be executed, created and cleaned up by the setup() and tearDown() methods. A fixture is common to all tests in the same class.

With your Product class, this would gives something along the lines of :

public class TestOrder extends TestCase
{
    // assume the fixtures creates the Product instances used for the tests here

    void TestValidOrder() 
    {
      // arrange - create an order
      // act - do something on the order - could be empty if testing the creation
      // assert - test the status of the order
    } 

}

A point of design: why doesn't the loop to compute the allowedQuantity and requiredQuantity belong to the Order class ?

Have a look at the bowling game episode , it's really a great tutorial to TDD. Last, you one can do TDD without resorting to mock objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM