Best way to automagically migrate tests from JUnit 3 to JUnit 4?
Asked Answered
Y

7

51

I have a bunch of JUnit 3 classes which extend TestCase and would like to automatically migrate them to be JUnit4 tests with annotations such as @Before, @After, @Test, etc.
Any tool out there to do this in a big batch run?

Yod answered 5/11, 2008 at 9:32 Comment(3)
Not answering the question, but you do realize that you can run JUnit3 tests under JUnit4 without modification, yes?Numismatist
Unless you use Junit3 TestSuite, in which case you're stuffed.Astronautics
If you keep those JUnit 3 tests around, other developers (depending on your team size) will keep copying them to new tests. And if they need to temporary disable a test (yes, the shouldn't, but sometimes they will need to), they 'll keep renaming it from testX to FIMXEtestX instead of annotating it with @Ignore. So you won't have any idea how many tests are currently being ignored (so how worried you should be). Just take any big project and look for regex "public void \w+test"Housewife
T
60

In my opinion, it cannot be that hard. So let's try it:

0. Imports

You need to import three annotations:

import org.junit.After;
import org.junit.Before;
import org.junit.Test;`

After you've made the next few changes, you won't need import junit.framework.TestCase;.

1. Annotate test* Methods

All methods beginning with public void test must be preceded by the @Test annotation. This task is easy with a regex.

2. Annotate SetUp and TearDown methods

Eclipse generates following setUp() method:

@Override
protected void setUp() throws Exception { }

Must be replaced by:

@Before
public void setUp() throws Exception { }

Same for tearDown():

@Override
protected void tearDown() throws Exception { }

replaced by

@After
public void tearDown() throws Exception { }

3. Get rid of extends TestCase

Remove exactly one occurence per file of the string

" extends TestCase"

4. Remove main methods?

Probably it's necessary to remove/refactor existing main methods that will execute the test.

5. Convert suite() method to @RunWithClass

According to saua's comment, there must be a conversion of the suite() method. Thanks, saua!

@RunWith(Suite.class)
@Suite.SuiteClasses({
  TestDog.class
  TestCat.class
  TestAardvark.class
})

Conclusion

I think, it's done very easy via a set of regular expressions, even if it will kill my brain ;)

Timecard answered 24/3, 2009 at 13:19 Comment(6)
The imports can be cleaned up automatically by Eclipse (Ctrl + Shift + O)Vertievertiginous
I don't think, that he wants to do this with a bunch of files. And they should be runnable.Timecard
I'd add conversion of suite() methods to @RunWith(Suite.class) @SuiteCkasses()Metaphrase
the setUp(), tearDown() methods have to be public in JUnit4Ekaterina
One additional step that I needed was to add @RunWith(JUnit4.class) to my class + import those things: import org.junit.runner.RunWith; import org.junit.runners.JUnit4;Naaman
need to convert the fail(string) and assertXX(...) calls to respective classes, as we do not extend TestCaseLimpet
H
39

Here are the actual regular expressions I used to execute furtelwart's suggestions:

// Add @Test
Replace:
^[ \t]+(public +void +test)
With:
    @Test\n    $1
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java

// Remove double @Test's on already @Test annotated files
Replace:
^[ \t]+@Test\n[ \t]+@Test
With:
    @Test
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java


// Remove all empty setUp's
Replace:
^[ \*]+((public|protected) +)?void +setUp\(\)[^\{]*\{\s*(super\.setUp\(\);)?\s*\}\n([ \t]*\n)?
With nothing
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java

// Add @Before to all setUp's
Replace:
^([ \t]+@Override\n)?[ \t]+((public|protected) +)?(void +setUp\(\))
With:
    @Before\n    public void setUp()
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java

// Remove double @Before's on already @Before annotated files
Replace:
^[ \t]+@Before\n[ \t]+@Before
With:
    @Before
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java


// Remove all empty tearDown's
Replace:
^[ \*]+((public|protected) +)?void +tearDown\(\)[^\{]*\{\s*(super\.tearDown\(\);)?\s*\}\n([ \t]*\n)?
With nothing
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java

// Add @After to all tearDown's
Replace:
^([ \t]+@Override\n)?[ \t]+((public|protected) +)?(void +tearDown\(\))
With:
    @After\n    public void tearDown()
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java

// Remove double @After's on already @After annotated files
Replace:
^[ \t]+@After\n[ \t]+@After
With:
    @After
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java


// Remove old imports, add new imports
Replace:
^([ \t]*import[ \t]+junit\.framework\.Assert;\n)?[ \t]*import[ \t]+junit\.framework\.TestCase;
With:
import org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport static org.junit.Assert.*;
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java


// Remove all extends TestCase
Replace:
[ \t]+extends[ \t]+TestCase[ \t]+\{
With:
 {
Regular Expression: on
Case sensitive: on
File name filter:
*Test.java



// Look for import junit.framework;
Find:
import junit\.framework
Manually fix
Regular Expression: on
Case sensitive: on


// Look for ignored tests (FIXME, disabled, ...)
Find:
public[ \t]+void[ \t]+\w+test
Manually fix
Regular Expression: on
Case sensitive: on


// Look for dummy/empty tests
Find:
public[ \t]+void[ \t]+test[\w\d]*\(\s*\)\s*\{\s*(//[^\n]*)?\s*\}
Manually fix
Regular Expression: on
Case sensitive: on

Note: it's important to do them in the order shown above.

Housewife answered 26/12, 2010 at 19:45 Comment(3)
Is there a way to run this?Naaman
Yes. In IntelliJ, do "Replace in path" (ctrl-shift-r) and fill in that dialog for each of these. For those that need to be done manually, use "Find in path" (ctrl-shift-f).Housewife
Same question for JUnit 4 to JUnit 5Housewife
A
6

We are in the middle of migrating a reasonably large code base to JUnit4. Since this is the second time I'm doing a migration such as this, I decided to save the code somewhere:

https://github.com/FranciscoBorges/junit3ToJunit4

It deals with more corner cases than the ones enumerated in answers above. Such as:

  • calls to TestCase.setUp() and TestCase.tearDown()
  • calls to TestCase(String) constructor within a sub-class constructor
  • calls to TestCase.assert* methods that moved to Assert.
  • fixing package names junit.framework to org.junit
  • etc
Ahl answered 24/5, 2013 at 9:10 Comment(0)
K
3

I don't know of a tool that would do this at the moment - I'd expect Eclipse to provide some plugin fairly shortly - but you could knock up a simple source tree exploring Java class that would do it for you if you only want to do a basic conversion. I had to write something similar to automatically generate skeleton test cases for a legacy application so I've got a fair amount of the support code already. You're welcome to use it.

Kraus answered 5/11, 2008 at 10:8 Comment(1)
Do you use java6 AST feature or eclipse AST ? Anyway, I am interested also: may be you may consider making this question a 'code-challenge' and publish your anonymized code on DZones ? (see stackoverflow.com/questions/190007 for an example of 'code-chalenge')Capelin
D
3

There are, to my best knowledge, no available migration tools (yet). What I know is this:

  • Last year, at OOPSLA in Nashville, was a paper about API migration but alas their tools seems not be openly available. I'll provide the link to the paper, (even though I dare it is of little use for you since it is rather theory heavy): "Annotation Refactoring: Inferring Upgrade Transformations for Legacy Applications".

  • Above, I wrote "no available tool (yet)" because my student Lea Hänsenberger is currently working on an auotmated API migration from, not onyl, JUnit 4 a to JExample, but also from JUnit 3 to JUnit 4. Please follow JExample on Twitter to get notified when she releases a first beta.

I hope this information was of help for you.

Duplicator answered 23/3, 2009 at 9:26 Comment(0)
A
1

Nice post. I did the upgrade using Netbeans with the following RegEx strings: (First line search-string, second one replace-string)

public void test
@Test\n    public void test

@Override\n.*protected void onSetUp
@Before\n    protected void onSetUp

@Override\n.*protected void onTearDown
@After\n    protected void onTearDown

Don't forget to flag the Regular Expression checkbox!

Alec answered 28/6, 2010 at 6:9 Comment(0)
A
1

If you want to automatically convert your Junit3 tests to Junit4, you can use the Vogella's Codemodify tool, available at this address:

TL;DR install and use it as follows:

Then, you can right-click any Junit3 test class, and select the Source > Convert to JUnit4 menu entry to convert your class to JUnit4.

enter image description here

The tool will automagically remove TestCase parent, outdated imports, add @Before, @After, @Test annotations, etc.

Amalamalbena answered 5/12, 2019 at 22:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.