Poor man’s JsUnit

Poor man’s JsUnit

In some sense the riches are really poor. Particularly, companies in the financial sector let their programmers access only their internal network. This might make their systems more secure. Another consequence is that developers cannot just download a library that they need. In order to do so a senior developer needs to convince his boss, the boss of his boss and the head of IT security too. This convincing thing is a long process with uncertain outcomes.  Senior developers would rather reinvent the wheel or just botch things up.

The project

Recently I was hacking a JavaScript project. Although we are poor men, this was quite a rich project: It used jQuery and a few other libs too. Of course the thing wasn’t too easy as I had to deal with the usual legacy code problems, e.g. the view and the business logic was one decent blob. None of these would’ve been a problem, however, the development-feedback loop was longer than I’d like it to be:

  1. editing Js, speculating how to get the most out of the next testing session
  2. building and deploying a war file
  3. testing the site from a browser

When I did this I already knew what TDD is and why is this good to me (to my boss, to the boss of my boss, to the CEO, to the end-users, etc.) There are many JavasScript unit testing tools, this SO page describes and evaluates lots of them. They explained which is good for what. They even discuss if js unit tests should run in browser. (It’s good to run them in browser because the production code runs there too. On the other hand, it’s bad to run them in browser because it’s a heavy dependency on the CI server.) I could download any of those libraries – to play with them at home. For the project at work it’s unimaginable.

The solution

This was my solution: I kept changing the source code until it worked well. Programming by coincidence, that’s what a poor man can do. With other wording: the customer is happy, however, we postponed to deal with the real problem. (We keep repaying the technical interests.)

I keep thinking what I could do differently the next time I work on this project. Rhino Unit gave me the idea: hey, Rhino can run JavaScript from java! Moreover, java 6 (and higher) doesn’t need any external lib either. We just say:

String javaScriptExpression = "helloWorld();";
Reader javaScriptFile = new StringReader(
    "function helloWorld() {\n"
        + "	println('Hello, World!');\n" + "}");
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");

engine.eval(javaScriptFile);
engine.eval(javaScriptExpression);

and it says “Hello, World!” By the way, the code above is a simplified version of this.

Unit tests

All we have to do to have unit tests is to wrap it into a JUnit test case, extract the reoccurring parts to the setUp() method, and voilà:

public class TestCalc {

    private ScriptEngine engine;

    @Before
    public void setUp() throws Exception {
        ScriptEngineManager factory = new ScriptEngineManager();
        engine = factory.getEngineByName("JavaScript");

        String[] sources = new String[] {
            "/com/tamasrev/Calc.js"
        };
        for (String src : sources) {
            Reader r = new InputStreamReader(getClass().getResourceAsStream(src));
            engine.eval(r);
        }
    }

    @Test
    public void testSum() throws Exception {
        //GIVEN
        String source = "sum(2, 3)";

        //WHEN
        Object result = engine.eval(source);

        //THEN
        assertEquals(5.0, result);
    }
}

Let’s take a closer look what these characters mean:

In the setUp() method we create a ScriptEngine and load the necessary JavaScript files into it. I suspect it’s enough to create the ScriptEngineManager only once; maybe it’s enough for the ScriptEngine too. However, the build time is still under 10 minutes so it’s good for now. If I were to write a library then I had to carefully evaluate and choose this sort of things.

The testSum() method creates JavaScript statements as Strings, runs it and calls a JUnit assert on the result. It’s all cool as long as we have only one assert pert test. Some people think that there shouldn’t be more asserts at all. Other people think that sometimes it’s OK to have more than one. I think that there are no hard rules for programming (this was a hard rule too).

We can retrieve more than one values as JavaScript objects. On the Java side it’s a NativeObject which is more or less a Map (focus on the less part). This is how it works:


@Test
public void testDividendAndRemainder() throws Exception {
    //GIVEN
    String source = "dividendWithRemainder(5, 2)";

    //WHEN
    Map result = (Map) engine.eval(source);

    //THEN
    assertEquals(2.0, result.get("dividend"));
    assertEquals(1.0, result.get("remainder"));
}

So we return key-value pairs to Java and we assert them the usual way. Asserting lists is an exercise to the reader.

Why

Why it this good for us? Because it lets us run JavaScript unit tests automatically. We don’t need no super cool hipster libs to do so. We don’t even need a browser either. It’s enough to have java 6, the good old JUnit and we are ready to go.

Why is this bad? First of all, these aren’t unit tests at all. As Michael Feathers explains in his legacy code book, unit tests are quick. They don’t talk over the network, they don’t mess with the file system, even less messing with a database. Unit tests run isolated. The tests that break these rules aren’t unit tests. However, he says, those tests can be useful.

Moreover, these are polyglot tests which deprives us from xUnits greatest power: that we can write the tests in the same language as the production code.

We cannot be entirely happy. Here we go again: this is what a poor man can do.

What’s next?

This is only a proof of concept. You can find the full java project here. The project is very small: every poor man can print it to paper and then type it into his machine on the internal network. The rest of you should use normal solutions, like JsUnit.

 

Advertisements

About tamasrev

A software developer, specialized in Java, addressing himself as generalist. A proud daddy.
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

3 Responses to Poor man’s JsUnit

  1. Hey Tamás,

    First of all, I like your posts, keep writing! But regarding to this one I’d rather use nodejs and mocha.

    Cheers,
    Tamás

  2. Pingback: Poor man’s template engine | tamasrev

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s