Skip to content
academia.sh

Course Intermediate

Build, Testing and the Ecosystem

Published

By the end of this course

Start course

01

Build Tools

The build tool's life cycle, target and task model; which class path a dependency scope makes a type visible on, that a transitive dependency can be required at run time without appearing at compile time, and what determines resolution when two candidates for the same name turn up; the compile-time counterpart of module boundaries; how the executable output that packaging produces carries the runtime path.

  1. 01 Build Tool Model The phase sequence a build tool derives from a declaration is fixed and unaffected by the declaration's writing order: three declared items yield four phases, and both a forward and a reversed writing of the same declaration derive the same four phases. Two class paths coming out of the same declaration — one for compiling, one for running — are separated by an annotation type kept at the source level: it never appears in the class file's constant pool, and it is never required on the runtime class path either.
  2. 02 Dependency Management The same source is first compiled against a compile class path and then run against a separate runtime class path: of six types, 1 turns out required only at compile time, 3 only at run time, 2 at both. Of four defects, 1 is a compile error, 1 is a runtime error, and 2 silently produce a wrong result without saying anything — one a choice tied to the order of two implementations of the same interface, the other the price of changing a constant without recompiling the caller.
  3. 03 Multi-Module Projects Of three boundary setups, one is caught at compile time, one at run time, one crosses the boundary silently without ever being caught. The limiting measurement shows why: Public and Internal are compiled into the same directory, and what actually builds the boundary is not the directory but a loader's allow list — of two class files in the same directory, one can be loaded while the other is rejected with a ClassNotFoundException.
  4. 04 Packaging and Executable Output The same archiving call produces both a self-sufficient archive and an archive dependent on an outside class: the first is sufficient on its own on the runtime class path, the second drops with a NoClassDefFoundError on its own and only runs once the missing directory is added. The entry point, too, lives not in the source but in the archive's own manifest: an undeclared archive produced from the same classes has no such information at all.

02

Testing

The test framework's life cycle and its assertions, where the class path the test sees diverges from the one production sees, fake dependencies taking the real type's place on the runtime class path, the same test body multiplied with data, the load setups with an external system add to the test path, and the executable counterpart of a test written in scenario language.

  1. 01 Unit Test Framework A small runner that calls setup, body and teardown calls in sequence is built by hand; the same assertion gives two different results when checked before and after teardown, and both are counted as run. When the same compiled test class runs against a class path missing the framework type, it measures that the test class path is a third, independent path.
  2. 02 Mocking The same compiled test is run once against a runtime class path where the real supplier type stands, and again against another runtime class path where a same-named fake type stands. The test gives two different results without being recompiled, and no error occurs; once the signature diverges, the same setup fails at run time and the cause does not appear in the test text.
  3. 03 Parameterized Tests A single body is called three times over a declared data set, and each call records whether its own row passed or failed. When setup is moved outside the loop and a single Store instance is shared across rows, which row passes becomes dependent on the data set's order, and the same three rows in reverse order make a different row pass.
  4. 04 Integration Tests The supplier mocked in the unit setup is put back on the runtime class path here with its real implementation, together with a second type the real implementation depends on; the type count the path carries rises from one to two. The same test body runs in two setups: in the unit setup a limit violation passes silently, in the integration setup the same request gives a run failure.
  5. 05 Behavior-Driven Testing A four-line scenario text is run against a step map; a step with no counterpart in the map is silently skipped in one run and halts the program in another. Even when the same four steps match completely, running against a map whose check steps have had their assertion removed still says "passed" over a wrong value.

03

Logging and Other JVM Languages

The trace the logging facade leaves in the caller's class file and the implementation's entry onto the runtime path through a declaration, the effect of log levels and structured records on readability in production, and other languages sharing the same runtime meeting on the same path through the class file format.

  1. 01 Logging Facade and Implementation The measurement reads the caller's class file's constant pool to show that it references the facade but never the implementation; the implementation enters the runtime class path through a service declaration, and when two implementations are present, the class path order decides which one is selected. The limiting measurement shows that when no implementation is found at all, the caller still compiles and runs, but produces no records.
  2. 02 Log Levels and Structured Logging How many records the same set of calls produces at two different thresholds is measured by running it, showing that the threshold is decided at runtime, not at the call site; the lesson demonstrates that a structured record's readability is measured not by field count but by whether the same field is present in every record. The limiting measurement shows that a call below the threshold is still evaluated when written with string concatenation, but not when written with a Supplier.
  3. 03 Other JVM Languages It is shown by running that a class produced directly in class file format, with no source text, is loaded and called just like a class compiled with javac, as long as it implements an interface; the caller's class file references the name of neither the real nor the generated implementation. The limiting measurement shows that a generated class file can carry a member name with no counterpart in Java syntax, and that this member can only be called through reflection.

Final exam

Build, Testing and the Ecosystem — Final Exam

In preparation

This course's question bank is not complete yet. The exam opens here automatically once enough questions are added.

Start typing to search.

↑↓ ↵ Esc navigate · open · close