mvysny / karibu-testing

Vaadin Server-Side Browserless Containerless Unit Testing
Apache License 2.0
105 stars 14 forks source link

Unable to create an instance of a parent layout with parameters #103

Closed MonsieurNiark closed 2 years ago

MonsieurNiark commented 2 years ago

Hello,

I am struggling while trying to make some tests with Mokito and Karibu.

I have a class with the annotation @Route, and a layout parameter :

@Route(value = ConstantesRoutes.MyRoute, layout = MainLayout.class) and I have a public constructor with two parameters autowired

@Autowired public MainView(final ManageSessionComponent userSession, final HttpSession httpSession) { this.userSession = userSession; this.httpSession = httpSession; ... }

But when I try to test a click on a button, I encounter this error : java.lang.IllegalArgumentException: Unable to create an instance of 'santeclair.valinor.vaadin.view.MainView'. Make sure the class has a public no-arg constructor.

Any idea how can I instanciate this parent layout ? Thank you :)

mvysny commented 2 years ago

Hi, I'm guessing that you're using Spring in your project. It looks like you're not using Spring Instantiator together with Karibu-Testing, but you're using the default instantiator which doesn't support injection. Please take a look at https://github.com/mvysny/vaadin-spring-karibu-testing/blob/main/src/test/java/com/example/application/AbstractAppTest.java

MonsieurNiark commented 2 years ago

I am using your template, in a simplified way

package com.project;

import org.junit.jupiter.api.BeforeEach;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;

import com.github.mvysny.kaributesting.v10.MockVaadin;
import com.github.mvysny.kaributesting.v10.Routes;
import com.vaadin.flow.component.UI;

import kotlin.jvm.functions.Function0;

//@Import(AbstractAppTest.MyTestConfiguration.class)
@SpringBootTest
@DirtiesContext
public abstract class AbstractAppTest {
    private static final Routes routes = new Routes().autoDiscoverViews("com.project");

    @BeforeEach
    public void setup() {
        final Function0<UI> uiFactory = UI::new;
        // final SpringServlet servlet = new MockSpringServlet(routes, ctx, uiFactory);
        MockVaadin.setup(routes, uiFactory);
    }
}

But i'm still getting error. I don't why it is trying to instanciate MainView without its parameters.

This is my test class :


public class AgeFrequentationViewTest extends AbstractAppTest {

    @Mock
    private EtudeOptiqueCompleteWebClient etudeOptiqueCompleteWebClient;

    @Mock
    private EtudeOptiqueResultatWebClient etudeOptiqueResultatWebClient;

    @Mock
    private VaadinSession vaadinSession;

    @Mock
    private BeforeEvent beforeEvent;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    private void execInMock(final Runnable test) {
        try (MockedStatic<VaadinSession> utilities = Mockito.mockStatic(VaadinSession.class)) {
            utilities.when(VaadinSession::getCurrent).thenReturn(vaadinSession);

            Mockito.when(vaadinSession.getAttribute(ConstantesVaadin.SESSION_USER_LOGGED)).thenReturn(CompteDto.builder().id(1)
                            .role(RoleEnum.USER)
                            .build());
            Mockito.when(vaadinSession.getAttribute(ConstantesVaadin.SESSION_USER_ORGANISATION)).thenReturn(OrganisationDto.builder().id(1).build());
            test.run();
        }
    }

    @Test
    void testSendResult() {
        execInMock(() -> {
            Mockito.when(etudeOptiqueCompleteWebClient.getEtudeByCompteByOrganisationAndEtude(1, 1, 1)).thenReturn(Optional.of(EtudeOptiqueCompleteDto.builder()
                            .idCompte(1)
                            .idOrganisation(1)
                            .build()));
            UI.getCurrent().navigate(ConstantesRoutes.ETUDE_IMPACT_OPTIQUE_AGE_FREQUENTATION + "/" + 1);

            _click(_get(Button.class, spec -> spec.withId(ConstanteEtudeDImpactOptiqueID.ETUDEIMPACT_AGEFREQ_BUTTON_SUIVANT)));
        });
    }
}
mvysny commented 2 years ago

Could it be that @Mock private VaadinSession vaadinSession; interferes with Karibu-Testing: it causes Vaadin to look up instantiator from the default VaadinSession as opposed to the VaadinSession object configured by Karibu-Testing? Try commenting out the mocking code and try again please.

MonsieurNiark commented 2 years ago

Yeah, it was a part of the problem :) I deleted it. Also, I added @ActiveProfiles("tests") to my AbstractAppTest (I work with profile to test with H2 database).

I also change two or three things about Mockito, but the main problem was resolved by you response. Thank you :)

mvysny commented 2 years ago

No problem 👍 the issue sounds to be resolved, I'll therefore close the ticket. But feel free to reopen if there's anything.