How to implement Integration Testing (with IDE too)

Hi. I’m looking for ways to implement Middleware Integration Test in my project. The documentation here: Middleware Integration Tests - CUBA Platform. Developer’s Manual doesn’t provide enough information. And no tutorials provide this either.

So, I hope if someone might help me with this questions please?

  • Documentation said: “Create a subclass in the core module of your project”. Regarding this, should I just proceed with creating new Class in core/src folder? Or should I make core/test folder? In the latter case, the IDE won’t work together with me. Since I have to manually input the code.

  • How to test Services? Is there anyway we can test Services? Documentation only give us how to test using Persistence interface. Which if we do it, then will be twice of work. Since we will duplicate the code.

should I just proceed with creating new Class in core/src folder? Or should I make core/test folder?

Create the core/test folder and then execute Build > Create or update {your IDE} project files. After that, IDE should recognize this folder as a tests root.

How to test Services?

Obtain references to your services via AppBeans.get(), for example:


package com.company.sales;

import com.haulmont.cuba.core.app.DataService;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.security.entity.User;
import org.junit.ClassRule;
import org.junit.Test;

import java.util.List;

import static org.junit.Assert.assertTrue;

public class MyTest {

    @ClassRule
    public static SalesTestContainer cont = new SalesTestContainer();
    
    @Test
    public void testMyService() throws Exception {
        DataService dataService = AppBeans.get(DataService.class);
        List<User> users = dataService.loadList(
                LoadContext.create(User.class).setQuery(
                        LoadContext.createQuery("select u from sec$User u")));
        assertTrue(!users.isEmpty());
    }
}
1 Like

My TestContainer use the same Database. Because my Service use EntityManager, and store Entity there. Is that the reason why I got this stacktrace? Any other way to fix this or maybe there’s other reason?


com.haulmont.cuba.core.global.RemoteException:
---
java.lang.NullPointerException: null
	at com.haulmont.cuba.core.sys.ServiceInterceptor.aroundInvoke(ServiceInterceptor.java:83)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:620)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:609)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
	at com.sun.proxy.$Proxy111.add(Unknown Source)
	at dev.pramajaya.hotel.RoomTest.newRooms(RoomTest.java:41)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:112)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:56)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
	at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:364)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
	at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

We’ve just added integration tests to the Sales sample application. Please take a look at it. Prior to running integration tests, execute startTestDb and createTestDb Gradle tasks in the command line or via the Studio Search dialog.

1 Like

Hi, I have tried to implement my test according to the example. When I try to run it, I’ll get the following error at the metadata assignment line:


org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cuba_Metadata' is defined
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:701)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1180)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1082)
	at com.haulmont.cuba.core.global.AppBeans.get(AppBeans.java:61)
	at com.haulmont.cuba.testsupport.TestContainer.metadata(TestContainer.java:144)
	at uk.co.wealthclub.clover.RefDataImpServiceBeanTest.setUp(RefDataImpServiceBeanTest.java:25)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)

I’m using the new 6.3.0 .RC2 platform. Could you please help, what could be wrong here?

Can you provide the source code of your test container and test class?

Hi Konstantin,

of course :

CurrencyDataTestContainer


/*
 * Copyright (c) 2016 clover
 */

import com.haulmont.cuba.testsupport.TestContainer;

import java.util.Arrays;

class CurrencyDataTestContainer extends TestContainer {

    public static final CurrencyDataTestContainer.Common INSTANCE = new CurrencyDataTestContainer.Common();

    public CurrencyDataTestContainer() {
        super();
        appPropertiesFiles = Arrays.asList(
                // List the files defined in your web.xml
                // in appPropertiesConfig context parameter of the core module
                "cuba-app.properties",
                "app.properties",
                // Add this file which is located in CUBA and defines some properties
                // specifically for test environment. You can replace it with your own
                // or add another one in the end.
                "test-app.properties");
        dbDriver = "org.postgresql.Driver";
        dbUrl = "jdbc:postgresql://docker-host/postgres";
        dbUser = "postgres";
        dbPassword = "postgres";

    }

    public static class Common extends CurrencyDataTestContainer {

        public static final CurrencyDataTestContainer.Common INSTANCE = new CurrencyDataTestContainer.Common();

        private static volatile boolean initialized;

        private Common() {
        }

        @Override
        public void before() throws Throwable {
            if (!initialized) {
                super.before();
                initialized = true;
            }
            setupContext();
        }

        @Override
        public void after() {
            cleanupContext();
            // never stops - do not call super
        }
    }

}

RefDataImpServiceBeanTest


import com.haulmont.cuba.core.global.*;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import uk.co.wealthclub.clover.service.RefDataImpServiceBean;

import java.io.IOException;

public class RefDataImpServiceBeanTest {
    @ClassRule
    public static CurrencyDataTestContainer cont = CurrencyDataTestContainer.Common.INSTANCE;

    private Metadata metadata;

    private RefDataImpServiceBean tester;

    @Before
    public void setUp() throws Exception {
        metadata = cont.metadata();
        tester = new RefDataImpServiceBean();
    }

    @Test
    public void importLatestCurrencyDataTest() {
        try {
            tester.importLatestCurrencyData();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Hi Gabor,

There was a mistake in the sample: two instances of the container were created because of the duplicated INSTANCE definition in SalesTestContainerclass. It might cause your problem depending on runtime conditions.

So just remove the line public static final CurrencyDataTestContainer.Common INSTANCE = … from your CurrencyDataTestContainer class, it must exist only inside the inner Common class.

Hi Konstantin,
I have done it, and it’s still the same :frowning:
Also if I enable AmazonS3FileStorage in spring xml it will say:


org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ETLImportWorker': Unsatisfied dependency expressed through field 'fileStorageService': Error creating bean with name 'cuba_FileStorage': Unsatisfied dependency expressed through field 'amazonS3Config': No bean named 'cuba_Configuration' is defined; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cuba_Configuration' is defined; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cuba_FileStorage': Unsatisfied dependency expressed through field 'amazonS3Config': No bean named 'cuba_Configuration' is defined; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cuba_Configuration' is defined

	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:569)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
	at com.haulmont.cuba.core.sys.CubaClassPathXmlApplicationContext.<init>(CubaClassPathXmlApplicationContext.java:27)
	at com.haulmont.cuba.core.sys.CubaCoreApplicationContext.<init>(CubaCoreApplicationContext.java:26)
	at com.haulmont.cuba.testsupport.TestContainer.initAppContext(TestContainer.java:367)
	at com.haulmont.cuba.testsupport.TestContainer.before(TestContainer.java:275)
	at uk.co.wealthclub.clover.CurrencyDataTestContainer$Common.before(CurrencyDataTestContainer.java:43)
	at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:46)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

but it works perfectly through the site…
It looks like if something wasn’t loaded…

Well, I’ve upgraded the sample to 6.3 and it broke with a similar exception.

The reason is that in 6.3+ you have to initialize the appComponents field in your test container like this:


public class SalesTestContainer extends TestContainer {

    public SalesTestContainer() {
        super();
        appComponents = new ArrayList<>(Arrays.asList(
                "com.haulmont.cuba"
        ));
        appPropertiesFiles = Arrays.asList(...

We’ll add this info to the release notes.

1 Like

Morning Konstantin,

Brilliant thanks, now it works perfectly! :slight_smile:

Hi Konstantin,

so like I’ve said it starts now, but now the injected properties are not being injected on the tested classes. (they will be null when running the test) Do you have a suggestion how to resolve this?

Thanks
Gabor

Hi Gabor,

Unfortunately, you cannot inject anything into test classes - it doesn’t work because test class is not under container control, it just uses the container. So use AppBeans.get() in setUp() or in test method to obtain references to services and other beans.

Hi Konstantin,
Sorry I meant inside the class which I want to test there are some injected properties, which apparently not being injected, when I run the test. For eg. : inside RefDataImpServiceBean I have


...
    @Inject
    protected DataManager dataManager;

which appears to be reluctant to get initialized, as when the test gets to the bit where it’s used inside the class it’s null:


    private List<Currency> getActiveCurrencyList() {
        LoadContext<Currency> lc = LoadContext.create(Currency.class)
                .setQuery(LoadContext.createQuery("select c from clover$Currency c"));

        return dataManager.loadList(lc);
    }

and the exception:


java.lang.NullPointerException
	at uk.co.wealthclub.clover.service.RefDataImpServiceBean.getActiveCurrencyList(RefDataImpServiceBean.java:242)
...

Thanks for helping!

I suppose you create a bean instance in the test instead of using an instance created by the container. Don’t use new MyBean(), use AppBeans.get(MyBean.class).

1 Like

Oh you are absolutely right, thank you! :slight_smile:

Now everything works fine :slight_smile:

I just thought to mention the cuba.restServicesConfig parameter might not have a default value anymore. At least for me upon upgrading to 6.3 my REST services have stopped working. Adding


cuba.restServicesConfig = cuba-rest-services.xml

to the app.properties has resolved the issue.

Hi,
yes, you’re right, there is no default value for the cuba.restServicesConfig property. That is because there is no a default service configuration file inside the platform. I guess, your own configuration is located in the file named cuba-rest-services.xml. If so, then it is correct to have your configuration file name explicitly defined in the app.properties file.

Hi Max,
Yes, but it was not like this, as it was working without setting this in pre-6.2, it’s even in the documentation, it has a default value:


cuba.restServicesConfig
This configuration parameter defines a set of files that contains a list of services available for application REST API calls.
The value is a list of file names, separated by spaces. The files are loaded according to the Resources interface rules.
The XSD of the file is available at http://schemas.haulmont.com/cuba/6.0/restapi-service-v2.xsd.
Used in the Web Portal block.
**Default value: cuba-rest-services.xml**
Example:
cuba.restServicesConfig = cuba-rest-services.xml app-rest-services.xml

Properties that list a set of files usually have a default value with the name of the file that exists in the platform, and you typically create your own config file and add its name to the default value. The cuba.restServicesConfig property had a default value by mistake. Sorry for the confusion. We will fix the documentation.