Skip to content

Instantly share code, notes, and snippets.

@flaviusstef
Forked from jbrains/SellOneItemTest.java
Created December 2, 2010 14:07
Show Gist options
  • Save flaviusstef/725342 to your computer and use it in GitHub Desktop.
Save flaviusstef/725342 to your computer and use it in GitHub Desktop.
package ca.jbrains.pos.test;
import org.junit.*;
import static org.junit.Assert.*;
import java.util.*;
public class SellOneItemTest {
private POSDisplay display = new POSDisplay();
private Sale sale;
public static class Sale {
private POSDisplay display;
private Map<String, String> pricesByBarcode = new HashMap<String, String> ();
public Sale(POSDisplay d, Map<String, String> pricesByBarcode) {
if (pricesByBarcode == null) {
throw new RuntimeException("Invalid price list");
}
display = d;
this.pricesByBarcode = pricesByBarcode;
}
public void onBarcode(String barcode) {
if ("".equals(barcode)) {
display.onEmptyBarcode();
return;
}
if (!pricesByBarcode.containsKey(barcode)) {
display.onInvalidBarcode(barcode);
return;
}
display.showPrice(pricesByBarcode.get(barcode));
}
}
public static class Display {
private String text;
public void setText(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
public static class POSDisplay extends Display {
public void onEmptyBarcode() {
setText("Scanning error: empty barcode");
}
public void onInvalidBarcode(String barcode) {
setText("No product with barcode " + barcode);
}
public void showPrice(String price) {
setText(price.equals("$0.00") ? "FREE" : price);
}
}
@SuppressWarnings("serial")
@Before
public void setUp() {
sale = new Sale(display, new HashMap<String, String>() {
{
put("123", "$12.50");
put("456", "$20.00");
put("333", "$0.00");
}
});
}
@Test
public void productFound() throws Exception {
assertForBarcodeDisplayShows("123", "$12.50");
}
@Test
public void anotherProductFound() throws Exception {
assertForBarcodeDisplayShows("456", "$20.00");
}
@Test
public void productNotFound() throws Exception {
assertForBarcodeDisplayShows("999", "No product with barcode 999");
}
@Test
public void emptyBarcode() throws Exception {
assertForBarcodeDisplayShows("", "Scanning error: empty barcode");
}
@Test
public void freeProductHasDistinctFormat() throws Exception {
assertForBarcodeDisplayShows("333", "FREE");
}
@Test(expected=RuntimeException.class)
public void nullProductListIsInvalid() {
new Sale(display, null);
}
private void assertForBarcodeDisplayShows(String barcode, String message) {
sale.onBarcode(barcode);
assertEquals(message, display.getText());
}
}
@jbrains
Copy link

jbrains commented Dec 7, 2010

First, my own observations, and then my comments on your comments.

  1. Why the inconsistency between lines 20 and 21? If you plan to write this.x = x; in constructors, then I recommend doing it uniformly.
  2. I'd like the exception you throw on a null pricesByBarcode to describe the problem more precisely.
  3. You have decided to design Sale to require non-null a pricesByBarcode even though there is a code path through onBarcode() that doesn't require pricesByBarcode. If you sometimes need one and sometimes don't, what might that say about the design?
  4. I see that you've moved methods responsible for displaying something into POSDisplay, which I quite like.
  5. I wonder why you named the methods in POSDisplay inconsistently. You have the imperative showPrice() but the event handling onInvalidBarcode() and onEmptyBarcode().
  6. You named the method onInvalidBarcode(), but is a barcode not in our catalog truly invalid? What other method name would describe this special case more accurately?
  7. Why have Display and POSDisplay as separate classes?
  8. I see that formatting $0 as "FREE" now appears in the view, which I find quite sensible. Now look at the method showPrice(String price). Should we model a price as text?

Otherwise, I like what you've done, and especially assertForBarcodeDisplayShows().

Regarding whether to write tests directly for POSDisplay, I think you can survive without it for a moment.

@jbrains
Copy link

jbrains commented Dec 7, 2010

I decided to make a small number of improvements at https://gist.github.com/731349 to show you an example of how I approach the code you're provided here. You can clone the entire repository to step through the commits and examine the differences.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment