Skip to content

WUnit Wollok Unit Testing

Fernando Dodino edited this page Aug 31, 2019 · 11 revisions

The whole flow of testing begins when a user requests a .wtest file to be tested:

Tests

Before starting

Every time you run a test, a program or REPL console, you are launching a new Wollok VM.

Pros

  • You can run any dangerous expression (like a neverending loop) without hanging the original VM. It is a safer approach.
  • It is Xtext recommended architecture

Cons

  • It is resource and time-consuming (at least 5-6 seconds, every time you want to run the tests)
  • It is hard to communicate both VMs. In order to do so, we use a lightweight library called LipeRMI

Let's make the overall picture of the whole process:

image

First part: launching tests (VM 2)

Wollok_Testing_Launch

Before Wollok Launcher starts, we need to setup some things: WollokLauncherParameters object has

  • a tests flag pointing to true value
  • and a testPort number
    • WollokTestLaunchDelegate sets testPort to WollokContextStateNotifier.listeningPort, from the UI-VM

WollokLauncherModule has sets the test reporter to the corresponding one:

  • WollokRemoteTestNotifier if launcher was fired from Wollok IDE (WollokContextStateNotifier is responsible for finding the first free port in the VM 1)
  • WollokConsoleTestsReporter if launcher was run from wollok-cli

Second part: Wollok Launcher (VM 2)

Wollok Launcher calls Wollok Interpreter which in turn calls to the WollokInterpreterEvaluator | WollokLauncherInterpreterEvaluator.

WollokInterpreterEvaluator delegates to several dispatch methods, but one of them is the main for tests/suites: WollokLauncherInterpreterEvaluator.evaluate(WFile). If you need to change the way tests are evaluated, this is the right place. Take a look into SuiteBuilder class.

override dispatch evaluate(WTest test) {
	try {
		test.elements.forEach [ expr |
			interpreter.performOnStack(expr, currentContext) [ | expr.eval ]
		]
		wollokTestsReporter.reportTestOk(test)
		null
	} catch (Exception e) {
		handleExceptionInTest(e, test)
	}
}

protected def WollokObject handleExceptionInTest(Exception e, WTest test) {
	if (e.isAssertionException) {
		wollokTestsReporter.reportTestAssertError(test, e.generateAssertionError, e.lineNumber, e.URI)
	} else {
		wollokTestsReporter.reportTestError(test, e, e.lineNumber, e.URI)
	}
	null
}
  • Every time a test passes, test reporter is notified (testOk)
  • The same happens if a test has an assertion error or fails
  • There are a lot of notifications for the test reporter inside WollokLauncherInterpreterEvaluator

Third part: test reporter notification (VM2 -> VM1)

WollokRemoteTestReporter collects every test result until the whole testing process finishes:

override finished(long timeElapsedInMilliseconds) {
	if (!processingManyFiles) {
		remoteTestNotifier.testsResult(testsResult, timeElapsedInMilliseconds)
	}
}

remoteTestNotifier is an instance variable, pointing to WollokRemoteUITestNotifier interface. The main implementation is in another project: wollok.ui.launch, in the UI VM (we mean, the VM where Wollok IDE is located):

image

Fourth part: UI WUnit (VM 1)

The main view of WUnit -xUnit implementation- is WollokTestResultView, an observer of WollokTestResults (the view model or application model), which has a container of WollokTestResult. Since RMI calls tend to be expensive, an optimization feature added in Wollok Freire sends the final results in a single message: testResults. These results are shown in a tree view container implemented by WTestTreeContentProvider and WTestTreeLabelProvider. It would be nice to extend this view into a multi-level tree, considering nested folders, describe and tests as possible nodes (nowadays only a single level is available).

Clone this wiki locally