Wrzesień
24
2009

Testowanie konwersacji

Słowa kluczowe: , , , | Kategorie: Seam Framework
No Gravatar

Omawiając testy integracyjne pominąłem kwestię konwersacji. Dlatego dzisiaj postanowiłem utworzyć i przetestować nowy komponent, działający w oparciu o konwersację.

Interfejs

Komponent będzie pozwalał na utworzenie nowego konta użytkownika. Jednak oprócz widoku formularza będzie on posiadał widok z pytaniem o potwierdzenie danych:


package pl.info.czerwinski;

import javax.ejb.Local;

@Local
public interface NewUser {
    public User getUser();

    public String createUser();
    public String sendUserData();
    public String confirmUser();

    public void removeComponent();
}

Akcja createUser będzie tworzyła nową instancję użytkownika i realizowała przekierowanie na widok formularza.

Po podaniu odpowiednich danych, użytkownik wywoła odpowiednim przyciskiem metodę sendUserData, która spowoduje wyświetlenie widoku z prośbą o potwierdzenie informacji.

Na sam koniec, confirmUser utworzy nowe konto użytkownika. Wówczas nastąpi przekierowanie na stronę główną aplikacji.

Komponent

Poniżej przedstawiam przykładową implementację interfejsu NewUser:

package pl.info.czerwinski;

import javax.ejb.Remove;
import javax.ejb.Stateful;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.security.management.IdentityStore;

@Stateful
@Name("newUser")
@Scope(ScopeType.CONVERSATION)
public class NewUserAction implements NewUser {
    static final String FORM_VIEW = "/newUserForm.xhtml";
    static final String CONFIRM_VIEW = "/newUserConfirm.xhtml";
    static final String END_VIEW = "/home.xhtml";

    @In private IdentityStore identityStore;

    private User user;

    public User getUser() {
        return user;
    }

    @Begin
    public String createUser() {
        user = new User();
        return FORM_VIEW;
    }

    public String sendUserData() {
        return CONFIRM_VIEW;
    }

    @End(beforeRedirect=true)
    public String confirmUser() {
        identityStore.createUser(
            user.getLogin(), user.getPassword());
        return END_VIEW;
    }

    @Remove
    public void removeComponent() {
    }
}

Najważniejsze, że komponent jest stanowy i znajduje się w kontekście konwersacji.

Testy

Klasa testów będzie się opierać o ten sam schemat, co przy zmianie hasła. Jednak tym razem dodam do niej jedno prywatne pole:


package pl.info.czerwinski;

import org.jboss.seam.mock.SeamTest;
import org.testng.annotations.Test;

public class NewUserTest extends SeamTest {
    private String id = null;
}

Identyfikator widoku (id) pozwala określić konwersację, której dotyczy dane żądanie JSF. Dzięki temu kolejne wywołania FacesRequest.run() będzie można logicznie powiązać ze sobą. Wystarczy wywoływać kolejne żądania w następujący sposób:


id = new FacesRequest("/foo.xhtml", id) {
    // […]
}.run();

Pierwszy przypadek testowy sprawdza działanie powyższej konwersacji:

  • uruchomienie konwersacji (↓ linie 5–10),
  • wprowadzenie danych do formularza (↓ linie 19–23),
  • wysłanie danych (↓ linie 24–29),
  • sprawdzenie poprawności danych (↓ linie 30–38),
  • potwierdzenie dodania nowego konta użytkownika (↓ linie 42–47):

@Test
public void testNewUser() throws Exception {
    // Click the "New user" link or button:
    id = new FacesRequest("/home.xhtml", id) {
        @Override
        protected void invokeApplication() throws Exception {
            assert invokeMethod("#{newUser.createUser}").equals(
                    NewUserAction.FORM_VIEW) :
                    "Wrong form view.";
        }
        @Override
        protected void renderResponse() throws Exception {
            assert getValue("#{newUser.user}") != null :
                    "No new user instance created.";
        }
    }.run();
    // Fill in the form and send the data:
    id = new FacesRequest(NewUserAction.FORM_VIEW, id) {
        @Override
        protected void updateModelValues() throws Exception {
            setValue("#{newUser.user.login}", "nowy");
            setValue("#{newUser.user.password}", "nowy");
        }
        @Override
        protected void invokeApplication() throws Exception {
            assert invokeMethod("#{newUser.sendUserData}").equals(
                    NewUserAction.CONFIRM_VIEW) :
                    "Wrong confirm view.";
        }
        @Override
        protected void renderResponse() throws Exception {
            assert getValue(
                    "#{newUser.user.login}").equals("nowy") :
                    "New user login incorrect.";
            assert getValue(
                    "#{newUser.user.password}").equals("nowy") :
                    "New user password incorrect";
        }
    }.run();
    // Confirm the data:
    id = new FacesRequest(NewUserAction.CONFIRM_VIEW, id) {
        @Override
        protected void invokeApplication() throws Exception {
            assert invokeMethod("#{newUser.confirmUser}").equals(
                    NewUserAction.END_VIEW) :
                    "End of conversation: wrong redirection view.";
        }
    }.run();
}

W drugiej metodzie testowej sprawdzam, czy można się zalogować do systemu używając danych nowego użytkownika:


@Test(dependsOnMethods="testNewUser")
public void testLogin() throws Exception {
    // Log in:
    new FacesRequest("/login.xhtml") {
        @Override
        protected void updateModelValues() throws Exception {
            setValue("#{credentials.username}", "nowy");
            setValue("#{credentials.password}", "nowy");
        }
        @Override
        protected void invokeApplication() throws Exception {
            invokeMethod("#{identity.login}");
        }
        @Override
        protected void renderResponse() throws Exception {
            assert (Boolean) getValue("#{identity.loggedIn}") :
                "Not logged in.";
        }
    }.run();
    // Log out:
    new FacesRequest("/home.xhtml") {
        @Override
        protected void invokeApplication() throws Exception {
            invokeMethod("#{identity.logout}");
        }
        @Override
        protected void renderResponse() throws Exception {
            assert (Boolean) getValue("#{not identity.loggedIn}") :
                "Still logged in.";
        }
    }.run();
}

Podsumowanie

Dzisiejszym artykułem zamykam temat testowania automatycznego aplikacji Seam.

Jest jeszcze sporo zagadnień, których nie omówiłem – między innymi konfiguracja testów w pliku XML czy klasa NonFacesRequest. Być może w przyszłości jeszcze do nich wrócę, lecz w najbliższej przyszłości zajmę się innymi zagadnieniami.

Napisz Komentarz

*