How to test Spring Data repositories?
Asked Answered
H

11

190

I want a repository (say, UserRepository) created with the help of Spring Data. I am new to spring-data (but not to spring) and I use this tutorial. My choice of technologies for dealing with the database is JPA 2.1 and Hibernate. The problem is that I am clueless as to how to write unit tests for such a repository.

Let's take create() method for instance. As I am working test-first, I am supposed to write a unit test for it - and that's where I bump into three problems:

  • First, how do I inject a mock of an EntityManager into the non-existing implementation of a UserRepository interface? Spring Data would generate an implementation based on this interface:

    public interface UserRepository extends CrudRepository<User, Long> {}
    

    However, I don't know how to force it to use an EntityManager mock and other mocks - if I had written the implementation myself, I would probably have a setter method for EntityManager, allowing me to use my mock for the unit test. (As for actual database connectivity, I have a JpaConfiguration class, annotated with @Configuration and @EnableJpaRepositories, which programmatically defines beans for DataSource, EntityManagerFactory, EntityManager etc. - but repositories should be test-friendly and allow for overriding these things).

  • Second, should I test for interactions? It is hard for me to figure out what methods of EntityManager and Query are supposed to be called (akin to that verify(entityManager).createNamedQuery(anyString()).getResultList();), since it isn't me who is writing the implementation.

  • Third, am I supposed to unit-test the Spring-Data-generated methods in the first place? As I know, the third-party library code is not supposed to be unit-tested - only the code the developers write themselves is supposed to be unit-tested. But if that's true, it still brings the first question back to the scene: say, I have a couple of custom methods for my repository, for which I will be writing implementation, how do I inject my mocks of EntityManager and Query into the final, generated repository?

Note: I will be test-driving my repositories using both the integration and the unit tests. For my integration tests I am using an HSQL in-memory database, and I am obviously not using a database for unit tests.

And probably the fourth question, is it correct to test the correct object graph creation and object graph retrieval in the integration tests (say, I have a complex object graph defined with Hibernate)?

Update: today I've continued experimenting with mock injection - I created a static inner class to allow for mock injection.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class UserRepositoryTest {

@Configuration
@EnableJpaRepositories(basePackages = "com.anything.repository")
static class TestConfiguration {

    @Bean
    public EntityManagerFactory entityManagerFactory() {
        return mock(EntityManagerFactory.class);
    }

    @Bean
    public EntityManager entityManager() {
        EntityManager entityManagerMock = mock(EntityManager.class);
        //when(entityManagerMock.getMetamodel()).thenReturn(mock(Metamodel.class));
        when(entityManagerMock.getMetamodel()).thenReturn(mock(MetamodelImpl.class));
        return entityManagerMock;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return mock(JpaTransactionManager.class);
    }

}

@Autowired
private UserRepository userRepository;

@Autowired
private EntityManager entityManager;

@Test
public void shouldSaveUser() {
    User user = new UserBuilder().build();
    userRepository.save(user);
    verify(entityManager.createNamedQuery(anyString()).executeUpdate());
}

}

However, running this test gives me the following stacktrace:

java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:101)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:319)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:212)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'entityManager' threw exception; nested exception is java.lang.IllegalArgumentException: JPA Metamodel must not be null!
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1493)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1197)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:684)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:121)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:250)
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
    ... 28 more
Caused by: org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'entityManager' threw exception; nested exception is java.lang.IllegalArgumentException: JPA Metamodel must not be null!
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:108)
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:62)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1489)
    ... 44 more
Haymes answered 2/5, 2014 at 19:54 Comment(0)
P
163

tl;dr

To make it short - there's no way to unit test Spring Data JPA repositories reasonably for a simple reason: it's way to cumbersome to mock all the parts of the JPA API we invoke to bootstrap the repositories. Unit tests don't make too much sense here anyway, as you're usually not writing any implementation code yourself (see the below paragraph on custom implementations) so that integration testing is the most reasonable approach.

Details

We do quite a lot of upfront validation and setup to make sure you can only bootstrap an app that has no invalid derived queries etc.

  • We create and cache CriteriaQuery instances for derived queries to make sure the query methods do not contain any typos. This requires working with the Criteria API as well as the meta.model.
  • We verify manually defined queries by asking the EntityManager to create a Query instance for those (which effectively triggers query syntax validation).
  • We inspect the Metamodel for meta-data about the domain types handled to prepare is-new checks etc.

All stuff that you'd probably defer in a hand-written repository which might cause the application to break at runtime (due to invalid queries etc.).

If you think about it, there's no code you write for your repositories, so there's no need to write any unittests. There's simply no need to as you can rely on our test base to catch basic bugs (if you still happen to run into one, feel free to raise a ticket). However, there's definitely need for integration tests to test two aspects of your persistence layer as they are the aspects that related to your domain:

  • entity mappings
  • query semantics (syntax is verified on each bootstrap attempt anyway).

Integration tests

This is usually done by using an in-memory database and test cases that bootstrap a Spring ApplicationContext usually through the test context framework (as you already do), pre-populate the database (by inserting object instances through the EntityManager or repo, or via a plain SQL file) and then execute the query methods to verify the outcome of them.

Testing custom implementations

Custom implementation parts of the repository are written in a way that they don't have to know about Spring Data JPA. They are plain Spring beans that get an EntityManager injected. You might of course wanna try to mock the interactions with it but to be honest, unit-testing the JPA has not been a too pleasant experience for us as well as it works with quite a lot of indirections (EntityManager -> CriteriaBuilder, CriteriaQuery etc.) so that you end up with mocks returning mocks and so on.

Puglia answered 3/5, 2014 at 9:16 Comment(6)
Do you have a link to a small example of an integration test with an in-memory database (e.g. h2) ?Intercontinental
The examples here use HSQLDB. Switching to H2 is basically a matter of exchanging the dependency in the pom.xml.Puglia
Thanks but I was hoping to see an example which pre-populates the database and/or really checks the database.Intercontinental
The link behind "written in a way" does not work anymore. Maybe you can update it?Intercontinental
So, you propose to use integration tests instead of unit tests for custom implementations too? And not write unit tests for them at all? Just to clarify. It's ok if yes. I understand the reason (too complex to mock all the things). I'm new to JPA testing so I just want to figure it out.Stabler
@djxak - Generally speaking: yes.Puglia
S
69

With Spring Boot + Spring Data it has become quite easy:

@RunWith(SpringRunner.class)
@DataJpaTest
public class MyRepositoryTest {

    @Autowired
    MyRepository subject;

    @Test
    public void myTest() throws Exception {
        subject.save(new MyEntity());
    }
}

The solution by @heez brings up the full context, this only bring up what is needed for JPA+Transaction to work. Note that the solution above will bring up a in memory test database given that one can be found on the classpath.

Strep answered 25/4, 2017 at 12:28 Comment(6)
This is an integration test, not unit test that OP mentionedReading
@IwoKucharski. You are right about the terminology. However: Given that Spring Data implements the interface for you, you are hard pressed to use Spring, and at that point it become an integration test. If I asked a question like this I probably also asked for a unit test without thinking about the terminology. Thus I did not see that as the main, or even central, point of the question.Strep
@RunWith(SpringRuner.class) is now already included in the @DataJpaTest.Isotropic
@IwoKucharski, why this is integration test, not unit test?Wizened
@Wizened @RunWith(SpringRunner.class starts the spring context which means it's checking the integration between several units. Unit test is testing a single unit -> single class. Then you write MyClass sut = new MyClass(); and test sut object (sut = service under test)Reading
Does a test using @DataJpaTest actually save to the database? If so, then, using this approach, would you delete the inserted row(s) afterwards as part of the test? Just wondering what the overall test approach would be where a unit (or integration) test actually inserts into the database.Cockle
U
28

This may come a bit too late, but I have written something for this very purpose. My library will mock out the basic crud repository methods for you as well as interpret most of the functionalities of your query methods. You will have to inject functionalities for your own native queries, but the rest are done for you.

Take a look:

https://github.com/mmnaseri/spring-data-mock

UPDATE

This is now in Maven central and in pretty good shape.

Uncertainty answered 21/2, 2015 at 6:46 Comment(0)
D
26

If you're using Spring Boot, you can simply use @SpringBootTest to load in your ApplicationContext (which is what your stacktrace is barking at you about). This allows you to autowire in your spring-data repositories. Be sure to add @RunWith(SpringRunner.class) so the spring-specific annotations are picked up:

@RunWith(SpringRunner.class)
@SpringBootTest
public class OrphanManagementTest {

  @Autowired
  private UserRepository userRepository;

  @Test
  public void saveTest() {
    User user = new User("Tom");
    userRepository.save(user);
    Assert.assertNotNull(userRepository.findOne("Tom"));
  }
}

You can read more about testing in spring boot in their docs.

Dianoia answered 21/3, 2017 at 3:2 Comment(5)
This is a fairly good example, but simplistic in my view. Are there any situations in which this test can even fail ??Co
Not this one per se, but suppose you wanted to test Predicates (which was my use case) it works quite well.Dianoia
for me repository is always null. Any help?Ferrigno
This is imho the best answer. This way you test the CrudRepo, the Entity and the DDL scripts which create the Entity's table(s).Subcontraoctave
I have written a test exactly like this one. It works perfectly when the implementation of the Repository utilizes jdbcTemplate. However, when I change the implementation for spring-data (by extending the interface from Repository), the test fails and userRepository.findOne returns null. Any ideas of how to solve this?Crossbreed
C
12

When you really want to write an i-test for a spring data repository you can do it like this:

@RunWith(SpringRunner.class)
@DataJpaTest
@EnableJpaRepositories(basePackageClasses = WebBookingRepository.class)
@EntityScan(basePackageClasses = WebBooking.class)
public class WebBookingRepositoryIntegrationTest {

    @Autowired
    private WebBookingRepository repository;

    @Test
    public void testSaveAndFindAll() {
        WebBooking webBooking = new WebBooking();
        webBooking.setUuid("some uuid");
        webBooking.setItems(Arrays.asList(new WebBookingItem()));
        repository.save(webBooking);

        Iterable<WebBooking> findAll = repository.findAll();

        assertThat(findAll).hasSize(1);
        webBooking.setId(1L);
        assertThat(findAll).containsOnly(webBooking);
    }
}

To follow this example you have to use these dependencies:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.197</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <version>3.9.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
Compare answered 7/9, 2018 at 6:31 Comment(0)
A
12

In the last version of spring boot 2.1.1.RELEASE, it is simple as :

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SampleApplication.class)
public class CustomerRepositoryTest {

    @Autowired
    CustomerRepository repository;

    @Test
    public void myTest() throws Exception {

        Customer customer = new Customer();
        customer.setId(100l);
        customer.setFirstName("John");
        customer.setLastName("Wick");

        repository.save(customer);

        List<?> queryResult = repository.findByLastName("Wick");

        assertFalse(queryResult.isEmpty());
        assertNotNull(queryResult.get(0));
    }
}

Complete code:

https://github.com/jrichardsz/spring-boot-templates/blob/master/003-hql-database-with-integration-test/src/test/java/test/CustomerRepositoryIntegrationTest.java

Anorak answered 1/1, 2019 at 22:59 Comment(5)
This is rather incomplete 'example': cannot be built, "integration" tests uses same configuration as production code. Ie. good for nothing.Edelstein
I apologize. I will whip me because of this error. Please try once again!Anorak
This also works with 2.0.0.RELEASE of Spring Boot.Cabala
You should use embedded db fot this testSleekit
I dont get how these tests save time or what they test? If your data.sql has injected test data - and for the above tests your cant change the data while the server is running what is the point?Chadbourne
W
5

With JUnit5 and @DataJpaTest test will look like (kotlin code):

@DataJpaTest
@ExtendWith(value = [SpringExtension::class])
class ActivityJpaTest {

    @Autowired
    lateinit var entityManager: TestEntityManager

    @Autowired
    lateinit var myEntityRepository: MyEntityRepository

    @Test
    fun shouldSaveEntity() {
        // when
        val savedEntity = myEntityRepository.save(MyEntity(1, "test")

        // then 
        Assertions.assertNotNull(entityManager.find(MyEntity::class.java, savedEntity.id))
    }
}

You could use TestEntityManager from org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager package in order to validate entity state.

Woodard answered 31/5, 2018 at 12:54 Comment(3)
Its always better spring to generate Id for the entity bean.Acid
For Java the second line is: @ExtendWith(value = SpringExtension.class)Evilminded
This gives me an error, java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your testDrachma
P
5

I solved this by using this way -

    @RunWith(SpringRunner.class)
    @EnableJpaRepositories(basePackages={"com.path.repositories"})
    @EntityScan(basePackages={"com.model"})
    @TestPropertySource("classpath:application.properties")
    @ContextConfiguration(classes = {ApiTestConfig.class,SaveActionsServiceImpl.class})
    public class SaveCriticalProcedureTest {

        @Autowired
        private SaveActionsService saveActionsService;
        .......
        .......
}
Propaedeutic answered 5/8, 2018 at 16:1 Comment(0)
G
3

you can use @DataJpaTest annotation that focuses only on JPA components. By default, it scans for @Entity classes and configures Spring Data JPA repositories annotated with @Repository annotation.

By default, tests annotated with @DataJpaTest are transactional and roll back at the end of each test.

//in Junit 5 @RunWith(SpringRunner.class) annotation is not required

@DataJpaTest
public class EmployeeRepoTest {

@Autowired
EmployeeRepo repository;
 
@Test
public void testRepository() 
{
    EmployeeEntity employee = new EmployeeEntity();
    employee.setFirstName("Anand");
    employee.setProject("Max Account");
     
    repository.save(employee);
     
    Assert.assertNotNull(employee.getId());
  }
}

Junit 4 Syntax will be along with SpringRunner class.

//Junit 4
@RunWith(SpringRunner.class)
@DataJpaTest
public class DataRepositoryTest{
//
}
Guardant answered 3/2, 2022 at 15:26 Comment(0)
H
1
springboot 2.4.5


import javax.persistence.EntityManager;
import javax.persistence.ParameterMode;
import javax.persistence.PersistenceContext;
import javax.persistence.StoredProcedureQuery;

@Repository
public class MyRepositoryImpl implements MyRepository {
    @Autowired
    @PersistenceContext(unitName = "MY_JPA_UNIT")
    private EntityManager entityManager;
    
    
    @Transactional("MY_TRANSACTION_MANAGER")
    @Override
    public MyEntity getSomething(Long id) {
    
        StoredProcedureQuery query = entityManager.createStoredProcedureQuery(
                "MyStoredProcedure", MyEntity.class);
        query.registerStoredProcedureParameter("id", Long.class, ParameterMode.IN);
        query.setParameter("id", id);

        query.execute();
        
        @SuppressWarnings("unchecked")
        MyEntity myEntity = (MyEntity) query.getResultList().stream().findFirst().orElse(null);
        return myEntity;
    }
}

import org.junit.jupiter.api.*;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;

import javax.persistence.EntityManager;
import javax.persistence.StoredProcedureQuery;
import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

@RunWith(MockitoJUnitRunner.Silent.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyRepositoryTest {

    @InjectMocks
    MyRepositoryImpl myRepository;

    @Mock
    private EntityManager entityManager;

    @Mock
    private StoredProcedureQuery storedProcedureQuery;
    
    @BeforeAll
    public void init() {
        MockitoAnnotations.openMocks(this);
        Mockito.when(entityManager.createStoredProcedureQuery(Mockito.any(), Mockito.any(Class.class)))
                .thenReturn(storedProcedureQuery);
    }

    @AfterAll
    public void tearDown() {
        // something
    }
    
    @Test
    void testMethod() throws Exception {
        Mockito.when(storedProcedureQuery.getResultList()).thenReturn(List.of(myEntityMock));

        MyEntity resultMyEntityList = myRepository.getSomething(1l);

        assertThat(resultMyEntityList,
                allOf(hasProperty("id", org.hamcrest.Matchers.is("1"))
                . . .
        );
    }
}
Hypocoristic answered 2/6, 2021 at 10:53 Comment(0)
C
1

In 2021 with a new initalized springboot 2.5.1 project, I'm doing it like:

...
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;


@ExtendWith(MockitoExtension.class)
@DataJpaTest
public class SomeTest {

    @Autowired
    MyRepository repo;

    @Test
    public void myTest() throws Exception {
        repo.save(new MyRepoEntity());
        /*...
        / Actual Test. For Example: Will my queries work? ... etc.
        / ...
        */
    }
}
Corelative answered 22/6, 2021 at 6:30 Comment(2)
I think this is useless testing. You are testing JPA and not your code. JPA is already tested and should be assumed so. Maybe I would create a separate test to check the mappings of the fields or checking the values of the columns in the annotations in order to detect a column value name change. This in case you are spinning up a in memory db instance on your own and loading table creation scriptsMazonson
I think your comment points into the right direction. The code above is meant to work as a starting point in the context of a springboot 2.5.1 application. The actual test code is not part of the example. The example is just about configuration.Corelative

© 2022 - 2024 — McMap. All rights reserved.