Tuesday, August 30, 2011

Kolejność budowania aplikacji w GWT i odpalanie testów (maven)

Nie umiałem dobrać tytułu. Wydaje mi się mylący, ale pościk jest o tym, że warto tak skonfigurować plugin GWT do mavena, aby aplikacja była kompilowana do JS dopiero po testach.
Wiadomo, że jeśli testy nie przechodzą, to nie ma sensu budować aplikacji. Jeśli omijamy testy (bywa i tak), to opisana niżej zmiana jest przeźroczysta.

W nowszych wersjach GWT (okolice 2.1.0) plugin buduje aplikację właśnie po testach, ale we wcześniejszych domyślnie odbywa się to w fazie compile. I to jest właśnie rozwiązanie. Należy przypiąć kompilację do JS w fazie po testach, ale przed budową paczki. Jeśli spojrzymy na pełną listę faz, to jest ich kilka "pomiędzy". Ja wpiąłem się w prepare-package i osiągnąłem zamierzony efekt. Poniżej typowa konfiguracja plugina mavenowego, w której określamy fazę uruchomienia (pominąłem konfigurację plugina):

                <plugins>
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>gwt-maven-plugin</artifactId>
                        <version>${gwt.maven.plugin.version}</version>
                        <executions>
                            <execution>
                                <phase>prepare-package</phase>
                                <goals>
                                    <goal>compile</goal>
                                </goals>
                            </execution>
                        </executions>



Dzięki temu oszczędziłem sporo czasu, bo zajmuję się projektem w którym budowanie aplikacji (8 permutacji!) zajmuje 4-5 minut. Do niedawna przy domyślnej konfiguracji najpierw kompilował się JS, a dopiero potem uruchamiały się testy. Szkoda tego czasu, tylko po to, aby w trakcie testów (które też trwają ok minuty), dowiedzieć się, że wysiłek był na marne.

A Mockito catch

Suppose we have such classes and interfaces

public class AddOrganizationAction implements Action {}
public class AddPersonToOrganizationAction implements Action {}


public interface DispatchAsync {
     void execute( Action action, AsyncCallback callback );
}


We're using the best mocking framework ;) Suppose we want to verify that code under test will call execute() with proper Action - AddOrganizationAction.
I found that many developers (including me!) check such condition with

verify(async).execute(any(AddOrganizationAction.class), any(AsyncCallback.class));

In such case AsyncCallback is not important for us. We just want to ensure that AddOrganizationAction will be passed. We run test and it's green. But suddenly if we put the code below into test it will be green too!

verify(async).execute(any(AddPersonToOrganizationAction .class), any(AsyncCallback.class));

Why? Because any() matcher doesn't check the instance of passed object to be equal to declared class (AddOrganizationAction in this case). Any() checks if passed object conforms to method signature. In this case any Action's child will do. And we have an erroneous test!
The proper matcher we'd like to use is isA() matcher that checks if passed object is instance of declared class (which means instance of class or it's children).

So the proper test should contain

verify(async).execute(isA(AddOrganizationAction.class), any(AsyncCallback.class));

Go now and search for any() usages and think about changing it to isA(). In 1 of 10 cases whenever I change all tests in a testcase to isA() usage, I find an error in implementation of logic under test. Luckily I know the catch and now you do :)

Ok. It's not really a catch but ignorance of all us developers that we don't read entire documentantation :)

Wednesday, August 3, 2011

Nowe wydanie Technology Radar z ThoughtWorks!

Jeśli zastanawiasz się czy technologie i narzędzia, z którymi pracujesz są trendy, akceptowalne, a może są przeżytkiem, to koniecznie zajrzyj do najnowszego, lipcowego wydania Technology Radar wydawanego co jakiś czas przez ThoughtWorks.
Może czas zmienić technologie? A może pracę...