Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Expand
titleDel 4 – Testing (10%)

I denne delen skal du skrive testkode for Value- og ValueSeries-klassene. Hensikten er å vise at du behersker testmetodikken, og du kan, men trenger ikke bruke JUnit-rammeverket.  

Oppgave a)

Skriv testkode for Value sin valueOf-metode.

Expand
titleLF
Code Block
themeEclipse
public void testValueOf() {
	Value value = Value.valueOf("2.0m");
	assertEquals(Unit.valueOf("m"), value.getUnit());
	assertEquals(2.0, value.getValue());
}
Oppgave b)

 Forklar med tekst og kode hvordan du kan teste at ValueSeries håndterer lyttere (av typen ValuesListener) og implementerer observerbarhet riktig.

Expand
titleLF
Code Block
themeEclipse
public class ValueSeriesTest extends TestCase implements ValuesListener {
	private ValueSeries values;
	
	protected void setUp() throws Exception {
		super.setUp();
		values = new ValueSeries(new Unit("m"));
		values.addValuesListener(this);
	}
	public void testValuesChanged() {
		values.appendValue(11);
		assertEquals(values, notified);
		notified = null;
		values.removeValuesListener(this);
		values.appendValue(12);
		assertEquals(null, notified);
	}
	
	private Values notified = null;
	
	@Override
	public void valuesChanged(Values values) {
		notified = values;
	}
}


Appendix: Specification of interfaces and classes and their methods. Some implementation details are provided, while other details are not given (since these are your task).
Expand
titleAppendix
Code Block
themeEclipse
languagejava
 package kont2015;
/**
 * A class for (scientific) units like meter (m), grams (g) and Kelwin (K).
 * Units may be derived from each other by a linear formula, e.g. km from m and C (Celcius) from Kelwin.
 * @author hal
 *
 */
public class Unit {
	
	/**
	 * Constructor for base units, e.g. meter, gram, kelwin etc.
	 * Initialises with the symbol, e.g. "m" for meters, "g" for grams, "K" for kelwin.
	 * @param symbol The symbol of this Unit, must contain only alphabetic characters.
	 * @throws IllegalArgumentException if the symbol contains characters that are not alphabetic
	 */
	public Unit(String symbol) throws IllegalArgumentException {
		...
	}
	
	/**
	 * Constructor for derived units, e.g. kilometer, milligram and Celcius, derived from meter, gram and Kelwin respectively.
	 * A derived unit includes the factor and offset for the linear formula for computing the base unit from the derived one.
	 * base-unit-value = derived-unit-value * factor + offset
	 * @param symbol The symbol for the derived Unit
	 * @param base The base unit, e.g. meter for kilometer, gram for milligram
	 * @param factor The factor in the formula, e.g. 1000 for km to m or 0.001 for mg to g.
	 * @param offset The offset in the formula.
	 * @throws IllegalArgumentException if the symbol contains characters that are not alphabetic
	 */
	public Unit(String symbol, Unit base, double factor, double offset) throws IllegalArgumentException {
		...
	}
	
	/**
	 * Constructor for derived units, e.g. kilometer, milligram and Celcius, derived from meter, gram and Kelwin respectively.
	 * A derived unit includes the factor and offset for the linear formula for computing the base unit from the derived one.
	 * base-unit-value = derived-unit-value * factor + offset
	 * @param symbol The symbol for the derived Unit
	 * @param base The base unit, e.g. meter for kilometer, gram for milligram
	 * @param factor The factor in the formula, e.g. 1000 for km to m or 0.001 for mg to g. The offset is set to 0.0.
	 * @throws IllegalArgumentException if the symbol contains characters that are not alphabetic
	 */
	public Unit(String symbol, Unit base, double factor) throws IllegalArgumentException {
		...
	}
	
	@Override
	public String toString() {
		return symbol;
	}
	
	/**
	 * Finds the first common unit from which both this and the other Unit is derived.
	 * If other is derived from this, then this is returned, or if this is derived from other, then other is returned.
	 * Otherwise it finds the first base unit that both are derived from.
	 * @param other The other unit.
	 * @return The first common unit that is a common base unit for both this and other.
	 */
	public Unit findCommonBaseUnit(Unit other) {
		...
	}
	/**
	 * Converts value from this unit to the other unit.
	 * @param value The value to convert.
	 * @param other The other unit, that value is converted to.
	 * @return value converted from this unit to the other unit
	 * @throws IllegalArgumentException if there is no common base unit.
	 */
	public double convert(double value, Unit other) throws IllegalArgumentException {
		Unit base = findCommonBaseUnit(other);
		if (base == null) {
			throw new IllegalArgumentException("Cannot convert from " + this + " to " + other);
		}
		double baseValue = convertToBase(value, base);
		return other.convertFromBase(baseValue, base);
	}
	/**
	 * Helper method for converting from this unit to a specific base unit.
	 * @param value The value to convert.
	 * @param base The base unit to convert to.
	 * @return The converted value.
	 */
	private double convertToBase(double value, Unit base) {
		if (this == base) {
			return value;
		}
		if (this.base == null) {
			throw new IllegalArgumentException(base + " is not a base for " + this);
		}
		return this.base.convertToBase(value * factor + offset, base);
	}
	/**
	 * Helper method for converting from a specific base unit to this unit.
	 * @param value The value to convert.
	 * @param base The base unit to convert from.
	 * @return The converted value.
	 */
	private double convertFromBase(double value, Unit base) {
		if (this == base) {
			return value;
		}
		if (this.base == null) {
			throw new IllegalArgumentException(base + " is not a base for " + this);
		}
		return this.base.convertFromBase(value, base) / factor - offset / factor;
	}
	// The currently supported predefined units, that are considered by the valueOf method
	private static Unit
		m = new Unit("m"),
		km = new Unit("km", m, 1000.0),
		dm = new Unit("dm", m, 0.1),
		cm = new Unit("cm", dm, 0.1),
		ALL_UNITS[] = {m, km, dm, cm};
	/**
	 * Finds the Unit for the given symbol among all predefined units.
	 * Currently supported units are m, km, dm, cm 
	 * @param symbol the symbol to search for, e.g. "m" or "dm"
	 * @return the Unit with the given symbol, or null, of no such Unit was found
	 */
	public static Unit valueOf(String symbol) {
		...
	}
}
package java.util.function;
/**
 * Represents a function that accepts two arguments and produces a result.
 * This is the two-arity specialization of {@link Function}.
 */
public interface BinaryOperator<T> {
    /**
     * Applies this function to the given arguments.
     *
     * @param t the first function argument
     * @param u the second function argument
     * @return the function result
     */
    T apply(T t1, T t2); 
}
package kont2015;
import java.util.function.BinaryOperator;
/**
 * A class representing a double value in a certain Unit.
 * Instances are immutable, i.e. cannot be modified once created.
 * @author hal
 *
 */
public class Value implements Comparable<Value> {
	
	/**
	 * Creates a new value with the provided Unit and (double) value.
	 * @param unit the Unit of the new Value
	 * @param value the double value of the new Value
	 */
	public Value(Unit unit, double value) {
		...
	}
	@Override
	public String toString() {
		return getValue() + unit.toString();
	}
	
	/**
	 * Returns this Value's Unit
	 * @return this Value's Unit
	 */
	... get... {
		...
	}
	/**
	 * Returns this Value's double value
	 * @return this Value's double value
	 */
	... get... {
		...
	}
	
	/**
	 * Returns a Value instance from the provided String.
	 * The format is a double (as parsed by Double.valueOf) followed by a Unit symbol (as parsed by Unit.valueOf), e.g. "1.0m" or "2.5km".
	 * @param s
	 * @return the String parses as a Value instance
	 */
	public static Value valueOf(String s) {
		...
	}
	
	/**
	 * Computes the sum of this and other (both Value objects).
	 * The Unit of the returned Value is the common base Unit of this and other's Units.
	 * Hence, both Value object's double values are properly converted before adding. 
	 * @param other the other Value
	 * @return a new Value object representing the sum of this and other
	 */
	public Value add(Value other) {
		...
	}
	/**
	 * Computes a new value that is the combination of this Value's double value and the provided double.
	 * The double values are combined using the provided BinaryOperator.
	 * The Unit of the returned Value is the this Value's Unit.
	 * @param other the double value to combine with this
	 * @return a new Value object representing the sum of this and other
	 */
	public Value compute(BinaryOperator<Double> op, double other) {
		...
	}	
	/**
	 * Computes the product of this Value and other (a double) using the compute method.
	 * @param other the other factor
	 * @return the product of this Value's double value and other (also a double)
	 */
	public Value mult(double other) {
		...
	}
	
	/**
	 * Compares this Value with other according the the requirements of Comparable.
	 * Note that this Value and other may have different Units.
	 * @throws IllegalArgumentException if this and other don't have a common base Unit.
	 */
	@Override
	public int compareTo(Value other) {
		...
	}
}
package kont2015;
/**
 * Interface implemented by classes wanting to be notified of changes to a Values object.
 * @author hal
 *
 */
public interface ValuesListener {
	public void valuesChanged(Values values);
}

package kont2015;
/**
 * An interface representing a sequence of doubles, all with the same Unit.
 * Implementing classes may support adding and removing elements. If modifiable,
 * the class must support notifying ValuesListeners.
 * @author hal
 *
 */
public interface Values extends Iterable<Double> {
	/**
	 * @return this Values' Unit
	 */
	public Unit getUnit();
	/**
	 * @return the number of values in the sequence.
	 */
	public int size();
	
	/**
	 * Computes the average of this Values object's double values.
	 * @return the average as a double (implicitly in this Values' Unit).
	 */
	public double average();
	
	/**
	 * Creates a new Values object where each element is the sum of corresponding elements in this and the other Values object.
	 * @param other the other Values
	 * @return a new Values object that represents the sum of this and other.
	 */
	public Values add(Values other);
	
	// ValuesListener support
	/**
	 * Adds a ValuesListener to be notified of changes to this Values object. 
	 * @param listener
	 */
	...
	/**
	 * Removes a previously added ValuesListener. 
	 * @param listener
	 */
	...
}
package kont2015;
/**
 * A class representing series of doubles, all with the same (unmodifiable) Unit.
 * A Values object can only be modified by appending another value.
 * @author hal
 *
 */
public class ValueSeries implements Values {
	/**
	 * Constructs a new ValueSeries object, with the provided Unit.
	 * @param unit
	 */
	public ValueSeries(...) {
		...
	}
	/**
	 * Appends the provided double to this ValueSeries. The double value is assumed to be in the Unit of this ValueSeries.
	 * @param value the double to append
	 */
	public void appendValue(double value) {
		...
	}
	/**
	 * Appends the provided Value to this ValueSeries, by first converting it to this ValueSeries' unit and then appending it.
	 * @param value the Value to append, after converting it to this ValueSeries' Unit.
	 */
	public void appendValue(Value value) {
		...
	}
	// Values methods
	...
}