generator-jhipster
generator-jhipster copied to clipboard
Add support to test junit with non temporary databases.
Overview of the issue
The test cases/code generated have many issues that will cause them to fail. I have never been able to run ./mvnw verify and have it pass when generating code for an oracle database (I have not tried other databases).
Looking in the test cases I see some bad assumptions such as:
This code seems to assume that after inserting a new entity and then retrieving a list of all entities using the repository.findAll() method that the new entry will be the last one. That is not the case with most databases, especially since there is no "order by" clause in the SQL that is executed for this query, the rows will be returned in no specific order.
@Test
@Transactional
void createCategory() throws Exception {
int databaseSizeBeforeCreate = categoryRepository.findAll().size();
// Create the Category
restCategoryMockMvc
.perform(
post(ENTITY_API_URL)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(category))
)
.andExpect(status().isCreated());
// Validate the Category in the database
List<Category> categoryList = categoryRepository.findAll();
assertThat(categoryList).hasSize(databaseSizeBeforeCreate + 1);
Category testCategory = categoryList.get(categoryList.size() - 1);
assertThat(testCategory.getName()).isEqualTo(DEFAULT_NAME);
assertThat(testCategory.getCreateUser()).isEqualTo(DEFAULT_CREATE_USER);
assertThat(testCategory.getCreateDate()).isEqualTo(DEFAULT_CREATE_DATE);
assertThat(testCategory.getModifyUser()).isEqualTo(DEFAULT_MODIFY_USER);
assertThat(testCategory.getModifyDate()).isEqualTo(DEFAULT_MODIFY_DATE);
}
This code assume that an entity will exist with an id of 1. That is not true if the database uses sequences, such as oracle, and the code uses 1 sequence for all entities, as JHipster generated code does. Only 1 table will get the sequence number of 1, all other tables/entities will wind up with their first record having some other id. (Also, using 1 sequence generator for the entire application and not using a different sequence generator for each table is a bad practice that not a lot of companies will allow, but it will work.)
@Test
@Transactional
void createCategoryWithExistingId() throws Exception {
// Create the Category with an existing ID
category.setId(1L);
int databaseSizeBeforeCreate = categoryRepository.findAll().size();
// An entity with an existing ID cannot be created, so this API call must fail
restCategoryMockMvc
.perform(
post(ENTITY_API_URL)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(category))
)
.andExpect(status().isBadRequest());
// Validate the Category in the database
List<Category> categoryList = categoryRepository.findAll();
assertThat(categoryList).hasSize(databaseSizeBeforeCreate);
}
Motivation for or Use Case
Running ./mvnw verify on a newly generated project, with no changes whosoever, should not ever fail.
Reproduce the error
Generate a project with JHipster using oracle, or perhaps another relational database, as the database and multiple entities. Then run ./mvnw verify
Related issues
Suggest a Fix
I am still researching this issue, and there are many problems with the test code, so I have do not have a fix at this time.
JHipster Version(s)
7.8.1, but this applies to all versions of jhipster.
JHipster configuration
This applies to all conficgutations
JHipster Version(s)
[email protected] C:\src\totalfact
+-- [email protected]
| `-- [email protected]
`-- [email protected]
JHipster configuration, a .yo-rc.json file generated in the root folder
.yo-rc.json file
{
"generator-jhipster": {
"applicationType": "monolith",
"authenticationType": "oauth2",
"baseName": "TotalFact",
"blueprints": [
{
"name": "generator-jhipster-primeng-blueprint",
"version": "7.0.4"
}
],
"buildTool": "maven",
"cacheProvider": "infinispan",
"clientFramework": "angularX",
"clientPackageManager": "npm",
"clientTheme": "none",
"clientThemeVariant": "",
"creationTimestamp": 1651244671759,
"databaseType": "sql",
"devDatabaseType": "oracle",
"dtoSuffix": "DTO",
"enableGradleEnterprise": false,
"enableHibernateCache": true,
"enableSwaggerCodegen": true,
"enableTranslation": true,
"entities": [
"UPC",
"UPCRule",
"PlatformType",
"Platform",
"PlatformDE",
"PlatformInst",
"PlatformList",
"Product",
"Release",
"Dimension",
"Category",
"Attribute",
"Section",
"FieldValue",
"Task",
"Step",
"PrivateNotes",
"ProtectedClass",
"Derivation",
"SourceType",
"Universe",
"EpsilonDataSource",
"Usage"
],
"entitySuffix": "",
"incrementalChangelog": true,
"jhiPrefix": "jhi",
"jhipsterVersion": "7.9.4",
"languages": ["en"],
"lastLiquibaseTimestamp": 1698155334000,
"messageBroker": false,
"nativeLanguage": "en",
"otherModules": [
{
"name": "generator-jhipster-primeng-blueprint",
"version": "7.0.4"
}
],
"packageFolder": "com/epsilon/totalfact",
"packageName": "com.epsilon.totalfact",
"pages": [],
"prodDatabaseType": "oracle",
"reactive": false,
"searchEngine": false,
"serverPort": "8080",
"serverSideOptions": ["enableSwaggerCodegen:true"],
"serviceDiscoveryType": false,
"skipCheckLengthOfIdentifier": false,
"skipClient": false,
"skipFakeData": false,
"skipServer": false,
"skipUserManagement": true,
"testFrameworks": ["gatling"],
"websocket": false,
"withAdminUi": true
}
}
JDL for the Entity configuration(s) entityName.json files generated in the .jhipster directory
JDL entity definitions
entity UPC {
upcKey String maxlength(15)
name String maxlength(250) required
description String maxlength(1024)
dataSource TextBlob
keywords TextBlob
userNotes TextBlob
restrictedResellerFlag Boolean
hidden Boolean
createUser String required
createDate Instant required
modifyUser String
modifyDate Instant
}
entity UPCRule {
ruleText TextBlob required
ruleDate Instant required
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PlatformType {
name String maxlength(10) required
description String
}
entity Platform {
primarySymbol String maxlength(128) required
fieldName String maxlength(250) required
fieldDescription String maxlength(1024)
fieldLength Integer
fieldValue String maxlength(100)
shortHeaderName String maxlength(10)
longHeaderName String maxlength(200)
inUse Boolean
premiumField Boolean
approvalRequired Boolean
royalty Boolean
token String maxlength(50)
sasKey String maxlength(10)
rateId String maxlength(10)
countType String maxlength(1)
kvp String maxlength(50)
caseable Boolean
sanRequired Boolean
waiverRequired Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PlatformDE {
ecapsKey Integer
defaultValue String maxlength(10)
usedInBilling Boolean
displayZeroCounts Boolean
areaFillinRequired Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PlatformInst {
pricingFlag Boolean
selectFlag Boolean
outputFlag Boolean
crosstabFlag Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PlatformList {
pricingFlag Boolean
selectFlag Boolean
outputFlag Boolean
crosstabFlag Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity Product {
name String
description String
productKey Integer min(0) max(999)
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity Release {
version String
releaseDate Instant
}
entity Dimension {
name String maxlength(128) required
description String
createUser String required
createDate Instant required
modifyUser String
modifyDate Instant
}
entity Category {
name String maxlength(128) required
createUser String required
createDate Instant required
modifyUser String
modifyDate Instant
}
entity Attribute {
fieldLevel String maxlength(128)
createUser String required
createDate Instant required
modifyUser String
modifyDate Instant
}
entity Section {
sectionKey String maxlength(10) required
name String maxlength(128) required
selfReported Boolean
modeled Boolean
thirdParty Boolean
areaLevel Boolean
compiled Boolean
updatedDaily Boolean
updatedWeekly Boolean
updatedBiWeeekly Boolean
updatedMonthly Boolean
updatedSixWeeeks Boolean
updatedQuatrerly Boolean
updatedSemiAnnually Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity FieldValue {
fieldValue String maxlength(25) required
valueDefinition String
averageMatchRate Float min(0) max(100)
displayOrder Integer
activeFlag Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity Task {
name String required
taskUser String maxlength(25) required
taskOrder Integer
showOnMainPage Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity Step {
completed Boolean
notes TextBlob
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PrivateNotes {
noteText TextBlob
noteDate Instant required
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity ProtectedClass {
code Integer min(0) max(9) required
name String maxlength(128)
description String maxlength(1024)
}
entity Derivation {
code String maxlength(10) required
name String maxlength(128)
description String maxlength(1024)
}
entity SourceType {
code String maxlength(10) required
name String maxlength(128)
description String maxlength(1024)
}
entity Universe {
code String maxlength(10) required
name String maxlength(128) required
}
entity EpsilonDataSource {
name String maxlength(128)
}
entity Usage (jhi_usage) {
action String required
parm String
user String maxlength(25) required
dateTime Instant required
}
relationship OneToOne {
PlatformDE{platform} to Platform{de}
PlatformInst{platform} to Platform{install}
PlatformList{platform} to Platform{list}
}
relationship OneToMany {
UPC{rules} to UPCRule{upc required}
Category{platform} to Platform{category}
UPC{platforms required} to Platform{upc required}
Dimension{categories required} to Category{dimension}
Platform{values required} to FieldValue{platform}
UPC{steps} to Step{uPC}
UPC{privateNotes} to PrivateNotes{upc required}
}
relationship ManyToOne {
UPC{attribute required} to Attribute
UPC{category required} to Category
UPC{protectedClass} to ProtectedClass
UPC{epsilonDataSource} to EpsilonDataSource
Platform{release} to Release
Platform{platformType} to PlatformType
PlatformDE{section} to Section
Product{platformType} to PlatformType
Dimension{universe} to Universe
Step{task} to Task
}
relationship ManyToMany {
UPC{sourceType} to SourceType{upc}
UPC{derivation} to Derivation{upc}
Platform{product} to Product{platform}
}
paginate UPC, UPCRule, PlatformType, Platform, PlatformDE, PlatformInst, PlatformList, Product, Release, Dimension, Category, Attribute, Section, FieldValue, Task, Step, PrivateNotes, ProtectedClass, Derivation, SourceType, Universe, EpsilonDataSource, Usage with pagination
service UPC, UPCRule, PlatformType, Platform, PlatformDE, PlatformInst, PlatformList, Product, Release, Dimension, Category, Attribute, Section, FieldValue, Task, Step, PrivateNotes, ProtectedClass, Derivation, SourceType, Universe, EpsilonDataSource, Usage with serviceClass
filter UPC, UPCRule, PlatformType, Platform, PlatformDE, PlatformInst, PlatformList, Product, Release, Dimension, Category, Attribute, Section, FieldValue, Task, Step, PrivateNotes, ProtectedClass, Derivation, SourceType, Universe, EpsilonDataSource, Usage
Environment and Tools
openjdk version "17.0.6" 2023-01-17 LTS OpenJDK Runtime Environment Microsoft-7209853 (build 17.0.6+10-LTS) OpenJDK 64-Bit Server VM Microsoft-7209853 (build 17.0.6+10-LTS, mixed mode, sharing)
git version 2.40.1.windows.1
node: v16.8.0
npm: 7.21.0
Entity configuration(s) entityName.json files generated in the .jhipster directory
This applies to any and all entities
Browsers and Operating System
This applies to all browsers and OSes.
- [X] Checking this box is mandatory (this is just to show you read everything)
This issue is stale because it has been open for too long without any activity. Due to the moving nature of jhipster generated application, bugs can become invalid. If this issue still applies please comment otherwise it will be closed in 7 days
Yes, this issue still applies and is still a problem
Tests cleans the entire database so when persisting a new entity it will be the last one.
We need a jhipster info output to reproduce the error.
JHipster Version(s)
[email protected] C:\src\totalfact
+-- [email protected]
| `-- [email protected]
`-- [email protected]
JHipster configuration, a .yo-rc.json file generated in the root folder
.yo-rc.json file
{
"generator-jhipster": {
"applicationType": "monolith",
"authenticationType": "oauth2",
"baseName": "TotalFact",
"blueprints": [
{
"name": "generator-jhipster-primeng-blueprint",
"version": "7.0.4"
}
],
"buildTool": "maven",
"cacheProvider": "infinispan",
"clientFramework": "angularX",
"clientPackageManager": "npm",
"clientTheme": "none",
"clientThemeVariant": "",
"creationTimestamp": 1651244671759,
"databaseType": "sql",
"devDatabaseType": "oracle",
"dtoSuffix": "DTO",
"enableGradleEnterprise": false,
"enableHibernateCache": true,
"enableSwaggerCodegen": true,
"enableTranslation": true,
"entities": [
"UPC",
"UPCRule",
"PlatformType",
"Platform",
"PlatformDE",
"PlatformInst",
"PlatformList",
"Product",
"Release",
"Dimension",
"Category",
"Attribute",
"Section",
"FieldValue",
"Task",
"Step",
"PrivateNotes",
"ProtectedClass",
"Derivation",
"SourceType",
"Universe",
"EpsilonDataSource",
"Usage"
],
"entitySuffix": "",
"incrementalChangelog": true,
"jhiPrefix": "jhi",
"jhipsterVersion": "7.9.4",
"languages": ["en"],
"lastLiquibaseTimestamp": 1698155334000,
"messageBroker": false,
"nativeLanguage": "en",
"otherModules": [
{
"name": "generator-jhipster-primeng-blueprint",
"version": "7.0.4"
}
],
"packageFolder": "com/epsilon/totalfact",
"packageName": "com.epsilon.totalfact",
"pages": [],
"prodDatabaseType": "oracle",
"reactive": false,
"searchEngine": false,
"serverPort": "8080",
"serverSideOptions": ["enableSwaggerCodegen:true"],
"serviceDiscoveryType": false,
"skipCheckLengthOfIdentifier": false,
"skipClient": false,
"skipFakeData": false,
"skipServer": false,
"skipUserManagement": true,
"testFrameworks": ["gatling"],
"websocket": false,
"withAdminUi": true
}
}
JDL for the Entity configuration(s) entityName.json files generated in the .jhipster directory
JDL entity definitions
entity UPC {
upcKey String maxlength(15)
name String maxlength(250) required
description String maxlength(1024)
dataSource TextBlob
keywords TextBlob
userNotes TextBlob
restrictedResellerFlag Boolean
hidden Boolean
createUser String required
createDate Instant required
modifyUser String
modifyDate Instant
}
entity UPCRule {
ruleText TextBlob required
ruleDate Instant required
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PlatformType {
name String maxlength(10) required
description String
}
entity Platform {
primarySymbol String maxlength(128) required
fieldName String maxlength(250) required
fieldDescription String maxlength(1024)
fieldLength Integer
fieldValue String maxlength(100)
shortHeaderName String maxlength(10)
longHeaderName String maxlength(200)
inUse Boolean
premiumField Boolean
approvalRequired Boolean
royalty Boolean
token String maxlength(50)
sasKey String maxlength(10)
rateId String maxlength(10)
countType String maxlength(1)
kvp String maxlength(50)
caseable Boolean
sanRequired Boolean
waiverRequired Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PlatformDE {
ecapsKey Integer
defaultValue String maxlength(10)
usedInBilling Boolean
displayZeroCounts Boolean
areaFillinRequired Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PlatformInst {
pricingFlag Boolean
selectFlag Boolean
outputFlag Boolean
crosstabFlag Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PlatformList {
pricingFlag Boolean
selectFlag Boolean
outputFlag Boolean
crosstabFlag Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity Product {
name String
description String
productKey Integer min(0) max(999)
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity Release {
version String
releaseDate Instant
}
entity Dimension {
name String maxlength(128) required
description String
createUser String required
createDate Instant required
modifyUser String
modifyDate Instant
}
entity Category {
name String maxlength(128) required
createUser String required
createDate Instant required
modifyUser String
modifyDate Instant
}
entity Attribute {
fieldLevel String maxlength(128)
createUser String required
createDate Instant required
modifyUser String
modifyDate Instant
}
entity Section {
sectionKey String maxlength(10) required
name String maxlength(128) required
selfReported Boolean
modeled Boolean
thirdParty Boolean
areaLevel Boolean
compiled Boolean
updatedDaily Boolean
updatedWeekly Boolean
updatedBiWeeekly Boolean
updatedMonthly Boolean
updatedSixWeeeks Boolean
updatedQuatrerly Boolean
updatedSemiAnnually Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity FieldValue {
fieldValue String maxlength(25) required
valueDefinition String
averageMatchRate Float min(0) max(100)
displayOrder Integer
activeFlag Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity Task {
name String required
taskUser String maxlength(25) required
taskOrder Integer
showOnMainPage Boolean
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity Step {
completed Boolean
notes TextBlob
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity PrivateNotes {
noteText TextBlob
noteDate Instant required
createUser String
createDate Instant
modifyUser String
modifyDate Instant
}
entity ProtectedClass {
code Integer min(0) max(9) required
name String maxlength(128)
description String maxlength(1024)
}
entity Derivation {
code String maxlength(10) required
name String maxlength(128)
description String maxlength(1024)
}
entity SourceType {
code String maxlength(10) required
name String maxlength(128)
description String maxlength(1024)
}
entity Universe {
code String maxlength(10) required
name String maxlength(128) required
}
entity EpsilonDataSource {
name String maxlength(128)
}
entity Usage (jhi_usage) {
action String required
parm String
user String maxlength(25) required
dateTime Instant required
}
relationship OneToOne {
PlatformDE{platform} to Platform{de}
PlatformInst{platform} to Platform{install}
PlatformList{platform} to Platform{list}
}
relationship OneToMany {
UPC{rules} to UPCRule{upc required}
Category{platform} to Platform{category}
UPC{platforms required} to Platform{upc required}
Dimension{categories required} to Category{dimension}
Platform{values required} to FieldValue{platform}
UPC{steps} to Step{uPC}
UPC{privateNotes} to PrivateNotes{upc required}
}
relationship ManyToOne {
UPC{attribute required} to Attribute
UPC{category required} to Category
UPC{protectedClass} to ProtectedClass
UPC{epsilonDataSource} to EpsilonDataSource
Platform{release} to Release
Platform{platformType} to PlatformType
PlatformDE{section} to Section
Product{platformType} to PlatformType
Dimension{universe} to Universe
Step{task} to Task
}
relationship ManyToMany {
UPC{sourceType} to SourceType{upc}
UPC{derivation} to Derivation{upc}
Platform{product} to Product{platform}
}
paginate UPC, UPCRule, PlatformType, Platform, PlatformDE, PlatformInst, PlatformList, Product, Release, Dimension, Category, Attribute, Section, FieldValue, Task, Step, PrivateNotes, ProtectedClass, Derivation, SourceType, Universe, EpsilonDataSource, Usage with pagination
service UPC, UPCRule, PlatformType, Platform, PlatformDE, PlatformInst, PlatformList, Product, Release, Dimension, Category, Attribute, Section, FieldValue, Task, Step, PrivateNotes, ProtectedClass, Derivation, SourceType, Universe, EpsilonDataSource, Usage with serviceClass
filter UPC, UPCRule, PlatformType, Platform, PlatformDE, PlatformInst, PlatformList, Product, Release, Dimension, Category, Attribute, Section, FieldValue, Task, Step, PrivateNotes, ProtectedClass, Derivation, SourceType, Universe, EpsilonDataSource, Usage
Environment and Tools
openjdk version "17.0.6" 2023-01-17 LTS OpenJDK Runtime Environment Microsoft-7209853 (build 17.0.6+10-LTS) OpenJDK 64-Bit Server VM Microsoft-7209853 (build 17.0.6+10-LTS, mixed mode, sharing)
git version 2.40.1.windows.1
node: v16.8.0
npm: 7.21.0
Tests cleans the entire database so when persisting a new entity it will be the last one.
We need a
jhipster infooutput to reproduce the error.
It is NOT POSSIBLE to "clean the entire database" when using real databases such as Oracle or MySql in a corporate environment. Permissions to drop or create tables are generally not provided by DBAs in such environments and cleaning the entire database will cause problems with every other application that uses the same database.
But thats how we setup the tests (and use testcontainers for). We treat the database in tests as ephemeral.
That is not a valid condition unless using h2 or some other temporary database.
Also, most databases DO NOT guarantee that the last value inserted into a table will be the last value selected from it unless you ORDER BY some value, such as a timestamp or a sequence/auto incremented value. Even if you "cleanse the entire database", once more than 1 row has been inserted.
Your test conditions are not valid.
But thats how we setup the tests (and use testcontainers for). We treat the database in tests as ephemeral.
Also, I can't use containers as the powers that be won't pay for docker licenses for our development windows laptops :(
We cannot support this feature because we do not have existing databases in our CI to test against. Our current testcontainers approach works pretty well. We accept PRs with improvements in this part.
@mshima, Unfortunately, the current testcontains approach does not work at all without purchasing a Docker Desktop license. This is something that our cheap architect will not allow :(
I have managed to finally update the project we have to JHipster 8.3.0 but none of the database unit tests work. In fact the application will not even start. The unit tests used to mostly pass using JHipster 7.9.4 and earlier (except for the ones I had to comment out due to circular references causing infinite loops).
Using Jhipster 8.3.0 the application fails immediately when running mvnw verify (even though simply running the application with ./mvnw works without issues) due to ClassNotFoundException:
If I change the SqlTestContainersSpringContextCustomizerFactory.java code back to what it was previously was with jhipster 7.9.4, then it fails attempting liquibase changes or migrations (mostly duplicate column, constraints, sequence not found, syntax errors, etc.) :(
I will try to get the time, eventually, to figure out how jhipster, and the testcontainers stuff, work and come up with a PR for this. In the meantime, I will probably just have to disable tests completely by having maven skip tests :(
@naris you can check the --dev-database-type h2Disk changes.
It disables TestContainers.