Cannot run REST API unit tests

Hello Cuba developers,

I only recently started working with the Cuba platform. For a client I am implementing unit tests for key middleware services. Together with a GitLab CI/CD built street this should allow us to gauge if changes would impact our application negatively.

However, I am having a hard time implementing tests for our REST API. Note, this is not the Cuba REST API that is standard and easy to use. Our middleware service has an additional trigger mechanism that will react to API calls and perform calls in turn to another system.

The unit tests calls I want to make were created with Postman. Postman and their Java equivalent run as intended when the Cuba application is running. That is not possible with GitLab. Instead I want to make use of the TestContainer API just as with the other unit tests. We currently use Cuba 6.10.17.

However running the Rest tests on their own fails because I cannot cast the current user to Staff.

Staff curUser = (Staff) userSession.getUserSession().getUser();

A breakpoint only reveals session with a user called “test_admin”. Whom I did not create. When running my Cuba app normally reveals UserSession with a User. I am assuming there is no current user, and only a default UserSession.

So how do I get around this problem. Can I explicitly create a UserSession with a User and use it with TestContainer? I am assuming there would be restrictions.

Also I understand this is an unusual question. The code in question is atypical and I am not able to share it. However, allow me to posit a separate question in the hopes this thread will yield result.

Can you create automated units tests for the Cuba REST API?

I know the first argument would be: “Why would you do that?” as performing CRUD operations Cuba defined entities is standard, but bare with me.

Hi,
In middleware integration tests bean UserSessionSource is overridden, and instead of standard implementation com.haulmont.cuba.client.testsupport.TestUserSessionSource is used.
As you can see from source code, it instantiates one user session with new User().

You can create your own similar implementation of this bean, register it in your test-spring.xml (additional spring.xml file which should be located in tests root and which can declare test-scope spring beans) and instantiate your own extended User class.

Thank you for the response Alex,

I will check out your suggestion and respond if it works.

James

Well I think I have made some progress, but I am stuck with a new problem as shown below. I have no idea if this issue is related or not.

No existing modules found. Please check if [${catalina.base}/webapps/cuba/WEB-INF/db] contains DB scripts.
java.lang.RuntimeException: No existing modules found. Please check if [${catalina.base}/webapps/cuba/WEB-INF/db] contains DB scripts.
	at com.haulmont.cuba.core.sys.dbupdate.ScriptScanner.getModuleDirs(ScriptScanner.java:136)
	at com.haulmont.cuba.core.sys.dbupdate.DbUpdaterEngine.getModuleDirs(DbUpdaterEngine.java:432)
	at com.haulmont.cuba.core.sys.dbupdate.DbUpdaterEngine.runRequiredInitScripts(DbUpdaterEngine.java:248)
	at com.haulmont.cuba.core.sys.dbupdate.DbUpdaterEngine.doUpdate(DbUpdaterEngine.java:229)
	at com.haulmont.cuba.core.sys.dbupdate.DbUpdaterImpl.doUpdate(DbUpdaterImpl.java:164)
	at com.haulmont.cuba.core.sys.dbupdate.DbUpdaterEngine.updateDatabase(DbUpdaterEngine.java:91)
	at com.haulmont.cuba.core.sys.dbupdate.DbUpdaterImpl.updateDatabaseOnStart(DbUpdaterImpl.java:87)
	at com.haulmont.cuba.core.sys.dbupdate.DbUpdaterImpl.applicationInitialized(DbUpdaterImpl.java:79)
	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.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:258)
	at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:177)
	at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:140)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
	at com.haulmont.cuba.core.sys.EventsImpl.publish(EventsImpl.java:33)
	at com.haulmont.cuba.testsupport.TestContainer.initAppContext(TestContainer.java:373)
	at com.haulmont.cuba.testsupport.TestContainer.before(TestContainer.java:277)
	at com.company.appname.AppnameTestContainer$Common.before(AppnameTestContainer.java:87)
	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.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
	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.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy1.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:108)
	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.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.lang.Thread.run(Thread.java:748)

Meanwhile I did think your posts and answers with Michael Renaud were interesting to read. Alas most of it relates to Cuba 7.

Cuba 7 : overriding bean in integration tests

If you configured property file chain and spring.xml chain properly, your tests should not try to automatically update database on start.
Because bean com.haulmont.cuba.testsupport.TestDbUpdaterImpl registered in CUBA’s test-spring.xml disables this behavior.

I’ve created sample project with working test on 6.10.

Test container constructor:

    public FoobarTestContainer() {
...
        appPropertiesFiles = Arrays.asList(
                "com/company/foobar/app.properties",

                "test-app.properties",
                "com/company/foobar/test-app.properties");
        initDbProperties();
        setSpringConfig("com/company/foobar/test-spring.xml");
    }

com/company/foobar/test-app.properties:

cuba.springContextConfig = +com/company/foobar/spring.xml test-spring.xml

com/company/foobar/test-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

    <bean id="cuba_UserSessionSource" class="com.company.foobar.MyTestUserSessionSource"/>

</beans>

foobar.zip (81.2 KB)

Thank you Alex,

I managed to create a number of unit tests using your suggestions!

Regards,

James