CS636 Class 10: more notes on pa1, JUnit (handout), intro transactions

Handout: JUnit Tutorial

Examples Of methods in domain classes other than getters and setters

Ex: In PizzaOrder, names for status values are provided String status String()

Also mutators: makeReady, receive, finish

music1 domain objects

Look at Cart to see only one getter, no setters

Look at Invoice and see only getters and setters: isProcessed is considered a form of getter for a boolean.

Look at LineItem:

We use BigDecimal for money, to keep pennies right.  See Representing Money.

One lineItem object has a certain product, at a certain price (lineItem.getProduct().getPrice), and a certain quantity. Then

                        itemTotal =  price * quantity   where price is a BigDecimal

                         For this multiplication, need to use BigDecimal method not “*”

Ex: LineItem has BigDecimal calculateItemTotal(), a non-getter method.

public BigDecimal calculateItemTotal() {

     // We can't use * to multiply with BigDecimal, but it knows how--
     BigDecimal total = product.getPrice().multiply(new BigDecimal(quantity));

     return total;
}


Goal for pa1: nice service API

So write stub methods of service API if no time to implement them.

If not enough time, skip AdminApp

But get SystemTest working in full if you can, and UserApp.

More notes on pa1--

Domain objects code can use ref’s to other domain objects especially if they are details of this object.

Product code can use its Tracks

Invoice owns its LineItems

Domain code is the code of the “model”. What the objects can do, also called their "behavior". In fact, domain objects with only getters and setters are called "anemic" POJOs: they are weaklings, only capable of passively holding data.

Service layer is in charge, but does a lot of work by calling the domain objects’ methods.

End of discussion directly relevant to pa1

JUnit

We’re using JUnit 4, which uses annotations, much neater than the older JUnit 3, but same capabilities.

Annotations in Java : see Wikipedia Java_annotation, Java tutorial

Built-in annotations : notes to the Java compiler

@Override - Checks that the method is an override. Causes a compile error if the method is not found in one of the parent classes or implemented interfaces.

Example: PizzaTopping.java:

        @Override
      public int hashCode()
      {
        return getToppingName().hashCode();
      }

Others :

Note: once the code compiles, then the annotation has no effect on the execution of the code once its executing. It might be selected for execution based on an annotation being read by some tool such as JUnit.

Non-built-in annotations: notes to other code processors

JUnit: @Test marks a method for JUnit to execute. It doesn’t affect how that code is executed. JUnit finds what tests to execute by using the Reflection API and finding the compiled annotations in the .class files.

Coming up: @Entity, etc. for JPA

See links from class web page to JUnit site with another tutorial, FAQ, Javadoc, etc.

see handout of first example, the calculator with a bug, and its unit test.

Note : this example is available as a project, linked from the class web page under Resources>JUnit

Also links to  a JUnit site with another tutorial, FAQ, Javadoc, etc.


How a JUnit test Executes

<Picture of two objects, one the object under test, of class Calculator, the other the tester object, of class CalculatorTest, also JUnit itself with ref to CalculatorTest.>

The test code in CalculatorTest calls the methods in Calculator, and JUnit arranges this setup and success/failure reporting from it, using the annotations as a guide for what to do.

How JUnit runs the JUnit test:

@BeforeClass method executes  (if there)

For each @Test method in the class:

   @Before method executes:   to bring object(s) to known starting state

   The @Test method executes  causing an experiment from that state

   @After method executes

@AfterClass method executes  (if there)

Note how JUnit is smart about exceptions. A unit test should not need a try/catch to test code that can throw exceptions. Look at testCreateTopping in PizzaOrderTest1.java as an example, another method there that expects an exception.  Neither needs try/catch in the test method.

Note another bug-catching technology: assertions. See http://docs.oracle.com/javase/7/docs/technotes/guides/language/assert.html

These are checks that are put in the regular source code but only get executed if –ea is used in the run “java –ea …”.  They are useful when unit testing is hard to do because of dependencies.

Quick example:   assert r<=RMAX: “r out of bounds”;  // after calc. of r

But unit testing is currently more popular than assertions in the Java world, and is believed to be healthy for the code because it promotes more independent objects, control of dependencies, “cleaner” code.

Handling Dependent Objects in Tests

Recall earlier discussion of using inversion of control with dependent objects. The hard part of unit testing is dealing with dependent objects. If one object does a new B() to create the dependent object, we're stuck with using a real B in testing, so it's hard to test A alone.

But if inversion of control is in use, we have more options. One way is to use “mock objects”, objects of a class that implements the same interface as the actual dependent, or is a subclass of it.  The implementation can be fake, that is, it can know what the test will ask of it, and just cook up a return for that.

We have HSQLDB as a wonderful mock DB, so we can test our DAOs with it, and once they are tested, test our service objects. We see that layering is helpful for testability.

Pizza1’s PizzaOrderDAOTest1, a JUnit 4 test using HSQLDB as a mock

Look at PizzaOrderTest1.java in dao package—

We’re using HSQLDB as a mock database here, simplifying our work immensely.

The @Begin method creates db (the DbDAO object) and pizzaOrderDAO objects (the "fixture")  separately for each test

(We could move db object creation to @BeforeClass)