Generics and Unit Testing
Generics
Generics extend Java's type system to allow "a type or method to operate on objects of various types while providing compile-time type safety." In different languages, they are called "templates."
Implementation:
Append the interace name with <T>. It's similar to a variable, so you can name it however you want. Treat it like any data type. It's a parameter, placeholder.
- Now when you declare it, you must specify the intended base type:
IndexedList<Integer> numbers;. This signals to the compiler that all values stored innumbersmust of typeInteger. <T>follows class name as well as interface names.- Fields should be defined with T
- Add documentation with
@param <T> the element type
Every ADT we work with will be a generic because we want it to work with every data type.
Generic is a reference type, so it will not work with primitive types. You must use wrapper classes.
- Note: every primitive type in Java has a corresponding reference tpe. For example,
inthasIntegerwrapper class that provides a way ot useintas anObject.
Generic Array
new T[size] will result in a compiler error. You must create an array of Object and then cast it to a generic array./
data = (T[]) new Object[size];
data = (T[]) Array.newInstance(Object.class, size);
Testing
In Intro to Algorithms: if you want to implement something, formally and rigorously prove algorithms using different methods for writing proofs. You must prove that a solution is correct.
Testing is not a replacement for proof. Testing can discover errors in implementation. We build confidence in correctness (each operation behaves as epxected for all inputs, including edge cases) when our testing does not fnd errors.
Find a systemmatic way to test. Document all the possibilities.
JUnit
JUnit is an open source library that is used in the industry to test programs. It's a separate library. All the files needed to configure JUnit are in the lib folder in intellij.
Two general preference on how to structure tests:
- Put them right next to the source code
- All the tests in a test folder. (gradel, marvel, ant all use this structure) (
src/test/java).
File should be named EntityNameTest.
For each class, make a test class. For each method make a test method and put them in corresponding packages. Annotate with @Test (part of JUnit) and ``@DisplayName()` (optionally).
Unit Testing: test a unit of code as independently as possible from other units of the code. It examines the smallest block of code that can be isolated for testing.
Normally, you write your code, then test it. However, we should write the test first then implement it. The benefit is that it makes you think about what the operation does. You can't just look at a problem and start coding. Gives you a second to pause. You can't write tests unless you clearly understand what a method does.
TFT: Test-first development. Write test first, then implement it.
TDD: Test-driven developement You write one test, implement just so that it passes. Write another test, then implement just enough. So on, and so forth.
Avoid using literals, instead use private final static int size = 5;.
JUnit lets you annotate a setup method that will be run before each unit test.
@BeforeEach
void setUp() {
numbers = new ArrayIndexedList<>(size, defaultValue);
}
Anatomy of each Unit Test
- Arrange everything wer need to run the test (instantiate).
- Act to set the test in motion; invoke the method to be tested with some input.
- Assert the output of the method under test checks against the expected outcome.
Linked from Data Structures