itemis Blog

Pro Tip: Implementing JUnit Test Cases in Xtend

Written by Tamas Miklossy | Jun 15, 2018

 

What makes a clean test? Three things. Readability, readability, and readability. Readability is perhaps even more important in unit tests than it is in production code. What makes tests readable? The same thing that makes all code readable: clarity, simplicity, and density of expression.
[Robert C. Martin: Clean Code - A Handbook of Agile Software Craftsmanship (page 124)]

 

Recently, the Eclipse GEF DOT Editor has been extended by the Rename Refactoring functionality. Following the Behaviour-Driven Development approach, its acceptance criteria have been specified first:

Feature: Rename Refactoring

  Scenario Outline:
    Given is the <dslFile>
    When renaming the <targetElement> to <newName>
    Then the dsl file has the content <newContent>.

    Examples:
      |  dslFile  |   targetElement   | newName | newContent |
      |-----------|-------------------|---------|------------|
      |  graph {  |                   |         |  graph {   |
      |    1      |     firstNode     |    2    |    2       |
      |  }        |                   |         |  }         |
      |           |                   |         |            |
      | digraph { |                   |         | digraph {  |
      |   1       |     firstNode     |    3    |   3        |
      |   1->2    |                   |         |   3->2     |
      | }         |                   |         | }          |
      |           |                   |         |            |
      | digraph { |                   |         | digraph {  |
      |   1       |    source node    |    3    |   3        |
      |   1->2    | of the first edge |         |   3->2     |
      | }         |                   |         | }          |
      |           |                   |         |            |


Thereafter, the test specification has been implemented in JUnit test cases:

class DotRenameRefactoringTests extends AbstractEditorTest {

	// ...

	@Test def rename_refactoring01() {
		'''
			graph {
				1
			}
		'''.
		testRenameRefactoring([firstNode], "2", '''
			graph {
				2
			}
		''')
	}

	@Test def rename_refactoring02() {
		'''
			digraph {
				1
				1->2
			}
		'''.
		testRenameRefactoring([firstNode], "3", '''
			digraph {
				3
				3->2
			}
		''')
	}

	@Test def rename_refactoring03() {
		'''
			digraph {
				1
				1->2
			}
		'''.
		testRenameRefactoring([sourceNodeOfFirstEdge], "3", '''
			digraph {
				3
				3->2
			}
		''')
	}

	// ...

	private def testRenameRefactoring(CharSequence it, (DotAst)=>NodeId element,
		String newName, CharSequence newContent) {
		// given
		dslFile.
		// when
		rename(target(element), newName).
		// then
		dslFileHasContent(newContent)
	}

	// ...

}


Thanks to the Xtend programming language, the entire DotRenameRefactoringTest test suite became readable, clean, and scales very well.

How did I do this? I did not simply write this program from beginning to end in its current form. To write clean code, you must first write dirty code and then clean it.

[Robert C. Martin: Clean Code - A Handbook of Agile Software Craftsmanship (page 200)]

Would you like to learn more about Clean Code, Behaviour-Driven and Test-Driven Development? Take a look at the (german) blog posts of my former colleague Christian Fischer, a very passionate software craftsman and agile coach.