@Email

TM69

Bekanntes Mitglied
Als was ist javax.validation.constraints.Email definiert?

Ich habe eine User-Klasse
Code:
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;

import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.hibernate.validator.constraints.Length;

@Entity
@Table(name = "user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @CreationTimestamp
    private LocalDateTime created_at;

    @JoinColumn(name = "created_by", referencedColumnName = "id")
    @ManyToOne(fetch = FetchType.LAZY)
    private User created_by;

    @OneToMany(mappedBy = "created_by", fetch = FetchType.LAZY)
    private List<User> createdUsers;

    @UpdateTimestamp
    private LocalDateTime updated_at;

    @JoinColumn(name = "updated_by", referencedColumnName = "id")
    @ManyToOne(fetch = FetchType.LAZY)
    private User updated_by;

    @OneToMany(mappedBy = "updated_by", fetch = FetchType.LAZY)
    private List<User> updatedUsers;

    @NotBlank
    @Length(min = 3, max = 255)
    private String firstname;

    @NotBlank
    @Length(min = 3, max = 255)
    private String lastname;

    @NotBlank
    @Length(min = 5, max = 255)
    @Email(message = "Email should be valid")
    private String email;

    @NotBlank
    @Length(min = 3, max = 255)
    private String password;

    public User() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public LocalDateTime getCreatedAt() {
        return created_at;
    }

    public void setCreatedAt(LocalDateTime created_at) {
        this.created_at = created_at;
    }

    public LocalDateTime getUpdatedAt() {
        return updated_at;
    }

    public void setUpdatedAt(LocalDateTime updated_at) {
        this.updated_at = updated_at;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public User getCreatedBy() {
        return created_by;
    }

    public void setCreatedBy(User created_by) {
        this.created_by = created_by;
    }

    public List<User> getCreatedUsers() {
        return createdUsers;
    }

    public void setCreatedUsers(List<User> userList) {
        this.createdUsers = userList;
    }

    public User getUpdatedBy() {
        return updated_by;
    }

    public List<User> getUpdatedUsers() {
        return updatedUsers;
    }

    public void setUpdatedUsers(List<User> updatedUsers) {
        this.updatedUsers = updatedUsers;
    }

    public void setUpdatedBy(User updated_by) {
        this.updated_by = updated_by;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", created_at=" + created_at + ", created_by=" + created_by + ", createdUsers="
                + createdUsers + ", updated_at=" + updated_at + ", updated_by=" + updated_by + ", updatedUsers="
                + updatedUsers + ", firstname=" + firstname + ", lastname=" + lastname + ", email=" + email
                + ", password=" + password + "]";
    }

}

und eine hierauf angewendete Test-Klasse
Code:
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class UserTest {

    private static Validator validator;

    @BeforeAll
    public static void init() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

    @Test
    void testUser() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertTrue(violations.isEmpty());
    }

    @Test
    void testUserWithFirstnameNullMustBeFalse() {
        User user = new User();

        user.setFirstname(null);
        user.setLastname("lastname");
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithFirstnameBlankMustBeFalse() {
        User user = new User();

        user.setFirstname("    ");
        user.setLastname("lastname");
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithFirstname2LengthMustBeFalse() {
        User user = new User();

        user.setFirstname(RandomStringUtils.random(2));
        user.setLastname("lastname");
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithFirstname3LengthMustBeTrue() {
        User user = new User();

        user.setFirstname(RandomStringUtils.random(3));
        user.setLastname("lastname");
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertTrue(violations.isEmpty());
    }

    @Test
    void testUserWithFirstname255LengthMustBeTrue() {
        User user = new User();

        user.setFirstname(RandomStringUtils.random(255));
        user.setLastname("lastname");
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertTrue(violations.isEmpty());
    }

    @Test
    void testUserWithFirstname256LengthMustBeFalse() {
        User user = new User();

        user.setFirstname(RandomStringUtils.random(256));
        user.setLastname("lastname");
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithLastnameNullMustBeFalse() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname(null);
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithLastnameBlankMustBeFalse() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname("     ");
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithLastname2LengthMustBeFalse() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname(RandomStringUtils.random(2));
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithLastname3LengthMustBeTrue() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname(RandomStringUtils.random(3));
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertTrue(violations.isEmpty());
    }

    @Test
    void testUserWithLastname255LengthMustBeTrue() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname(RandomStringUtils.random(255));
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertTrue(violations.isEmpty());
    }

    @Test
    void testUserWithLastname256LengthMustBeFalse() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname(RandomStringUtils.random(256));
        user.setEmail("email@email.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithWrongEmailMustBeFalse() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail("emailemail.com");
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithEmailNullMustBeFalse() {
        User user = new User();

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail(null);
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

    @Test
    void testUserWithEmailLength255MustBeTrue() {
        User user = new User();

        String email = RandomStringUtils.random(229) + "@" + RandomStringUtils.random(22) + ".com";
        assertTrue(email.length() == 255);

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail(email);
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertTrue(violations.isEmpty());
    }

    @Test
    void testUserWithEmailLength256MustBeFalse() {
        User user = new User();

        String email = RandomStringUtils.random(229) + "@" + RandomStringUtils.random(22) + ".com";
        assertTrue(email.length() == 256);

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail(email);
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertFalse(violations.isEmpty());
    }

}

Für die Funktion testUserWithEmailLength255MustBeTrue(), dass
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
Obwohl die Funktion eigentlich True ergeben müsste. Deshalb meine Frage wie ist @Email definiert? Im Netz konnte ich nichts finden.
 
K

kneitzel

Gast
Ähm - Nur mal kurz zur Info:
RandomStringUtils.random(229) + "@" + RandomStringUtils.random(22) + ".com";
Du hast also 229 Zeichen + 1 Zeichen + 22 Zeichen + 4 Zeichen -> 256 Zeichen.
Bei Max 255 ist das also ein Zeichen zu viel!
 

TM69

Bekanntes Mitglied
Okay, ich habe die test-Funktion abgeändert:
Code:
@Test
    void testUserWithEmailLength255MustBeTrue() {
        User user = new User();

        String email = RandomStringUtils.randomAlphabetic(229) + "@" + RandomStringUtils.randomAlphabetic(22) + ".com";
        assertTrue(email.length() == 255, "Email is: " + email);

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail(email);
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertTrue(violations.isEmpty());
    }
Immer noch das gleiche Problem:
org.opentest4j.AssertionFailedError: Email is: oyUxAWsGyHgXwVQTbQkIaYZyJqEvKOwZONsZbwBrofoljzlaRgsVaWkdYdcztgoDYlKtFBuyZAAfrsrzLRIKLMYFtyvbcoCBHZYIUkHXsJINwPSaYCBItSAVfLvnugJvZjUvNtOmvVfaHeiceECufHJUcpWNeKCWpJHcNtfcjZnmrvuFcGHojbkeXdgXYboobspPCnHTgHUcOkvKfiDmabEPORUMNUxpEmDeM@kChnCRYOFSyBBesLteHSFu.com ==> expected: <true> but was: <false>
 
K

kneitzel

Gast
Und mal eine Frage ganz am Rande:
Schreibt Ihr eure Unit-Tests ohne Logging? Ich schreibe in meine Tests auch immer einfache log Anweisungen um dann z.B. nicht nur ein "AssertionFailedError" zu sehen sondern halt auch Details. Sprich: Ich hätte hier auch die Violation ins Log geschrieben und beim failed Test hätte ich dann direkt gesehen, was denn angemeckert worden ist....

Daher wäre hier meine Frage, wie ihr das seht.
 

TM69

Bekanntes Mitglied
Ähm - Nur mal kurz zur Info:
RandomStringUtils.random(229) + "@" + RandomStringUtils.random(22) + ".com";
Du hast also 229 Zeichen + 1 Zeichen + 22 Zeichen + 4 Zeichen -> 256 Zeichen.
Bei Max 255 ist das also ein Zeichen zu viel!
Da hast du vollkommen recht, hatte mich wohl verzählt.
Habs deshalb nochmal abgeändert:
Code:
    @Test
    void testUserWithEmailLength255MustBeTrue() {
        User user = new User();

        String email = RandomStringUtils.randomAlphabetic(228) + "@" + RandomStringUtils.randomAlphabetic(22) + ".com";
        assertTrue(email.length() == 255, "Email is: " + email);

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail(email);
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        assertTrue(violations.isEmpty());
    }
Stoße aber immer noch auf den Fehler:
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
Was mich jetzt allerdings etwas irritiert ist, das die Meldung nicht ausgegeben wird o_O
 

httpdigest

Top Contributor
Wie wär's, wenn du dir die zurückgegebenen ConstraintViolations mal ausgeben lässt, um zu sehen, was genau denn da jetzt fehlschlägt?
 

TM69

Bekanntes Mitglied
Wie wär's, wenn du dir die zurückgegebenen ConstraintViolations mal ausgeben lässt, um zu sehen, was genau denn da jetzt fehlschlägt?
Wie meinst du ausgeben? So:
Code:
assertTrue(violations.isEmpty(), violations.toString());
Ergibt:
org.opentest4j.AssertionFailedError: [ConstraintViolationImpl{interpolatedMessage='Email should be valid', propertyPath=email, rootBeanClass=class com.metho.builder.entities.User, messageTemplate='Email should be valid'}] ==> expected: <true> but was: <false>
 
Zuletzt bearbeitet:

httpdigest

Top Contributor
Mit "ConstraintViolations ausgeben" meine ich, dass du dir die ConstraintViolations ausgeben lassen sollst, um zu erkennen, wo denn das Validation Framework genau rummeckert.
Java:
Set<ConstraintViolation<User>> violations = validator.validate(user);
System.out.println(violations);
 
K

kneitzel

Gast
Also die wichtige RFC ist hier die 3696, welche die Namensgebung definiert. Section 3 behandelt Email Addressen:
https://tools.ietf.org/html/rfc3696#section-3

Die Längenbeschränkung ist hier so angegeben:
In addition to restrictions on syntax, there is a length limit on
email addresses. That limit is a maximum of 64 characters (octets)
in the "local part" (before the "@") and a maximum of 255 characters
(octets) in the domain part (after the "@") for a total length of 320
characters. Systems that handle email should be prepared to process
addresses which are that long, even though they are rarely
encountered.

Also vor dem @ dürfen nur 64 Zeichen sein und nach dem @ 255 Zeichen. Wichtig ist hier auch die Ergänzung von octets, denn Unicode-Zeichen werden ja auch seit einiger Zeit erlaubt. Und die Zählen dann ggf. wie mehrere Zeichen.
 

TM69

Bekanntes Mitglied
Mit "ConstraintViolations ausgeben" meine ich, dass du dir die ConstraintViolations ausgeben lassen sollst, um zu erkennen, wo denn das Validation Framework genau rummeckert.
Java:
Set<ConstraintViolation<User>> violations = validator.validate(user);
System.out.println(violations);
Hier nochmal erweiterte Version
Code:
    @Test
    void testUserWithEmailLength255MustBeTrue() {
        User user = new User();

        String email = RandomStringUtils.randomAlphabetic(228) + "@" + RandomStringUtils.randomAlphabetic(22) + ".com";
        assertTrue(email.length() == 255, "Email is: " + email);

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail(email);
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        System.out.println(violations);
        assertTrue(violations.isEmpty(), violations.toString());
    }
Was ich jetzt erwartet hätte das er mir sysout in der Konsole ausgibt. Dieses passiert aber nicht.
Code:
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.2.RELEASE)

2020-01-29 20:17:17.727  INFO 15012 --- [           main] com.metho.builder.entities.UserTest      : Starting UserTest on xxx - Rechner with PID 15012 (started by tomth in C:\Projekte\java\Builder)
2020-01-29 20:17:17.728  INFO 15012 --- [           main] com.metho.builder.entities.UserTest      : No active profile set, falling back to default profiles: default
2020-01-29 20:17:18.440  INFO 15012 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2020-01-29 20:17:18.519  INFO 15012 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 71ms. Found 3 JPA repository interfaces.
2020-01-29 20:17:18.856  INFO 15012 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-01-29 20:17:19.149  INFO 15012 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-01-29 20:17:19.221  INFO 15012 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.4.9.Final}
2020-01-29 20:17:19.366  INFO 15012 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-01-29 20:17:19.505  INFO 15012 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-01-29 20:17:19.698  INFO 15012 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-01-29 20:17:19.722  INFO 15012 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2020-01-29 20:17:20.362  INFO 15012 --- [           main] org.hibernate.tuple.PojoInstantiator     : HHH000182: No default (no-argument) constructor for class: com.metho.builder.entities.Project (class must be instantiated by Interceptor)
Hibernate: drop table if exists languages
Hibernate: drop table if exists projects
Hibernate: drop table if exists user
Hibernate: create table languages (id bigint not null auto_increment, created_at datetime, iso varchar(255) not null, name varchar(255) not null, updated_at datetime, created_by bigint, updated_by bigint, primary key (id)) engine=MyISAM
Hibernate: create table projects (id bigint not null auto_increment, created_at datetime, directory varchar(255), name varchar(255), path varchar(255), updated_at datetime, created_by bigint, updated_by bigint, primary key (id)) engine=MyISAM
Hibernate: create table user (id bigint not null auto_increment, created_at datetime, email varchar(255), firstname varchar(255), lastname varchar(255), password varchar(255), updated_at datetime, created_by bigint, updated_by bigint, primary key (id)) engine=MyISAM
Hibernate: alter table languages add constraint FK6pb75mfcy4xyf5olu4j0abcoi foreign key (created_by) references user (id)
Hibernate: alter table languages add constraint FKn3mumfixnk1277loo0yy5lc4l foreign key (updated_by) references user (id)
Hibernate: alter table projects add constraint FKhe2fjwmi248e1kkspnk0plhu7 foreign key (created_by) references user (id)
Hibernate: alter table projects add constraint FKdq1cwyl5wl23g23jxh6si17u7 foreign key (updated_by) references user (id)
Hibernate: alter table user add constraint FKdltbr5t0nljpuuo4isxgslt82 foreign key (created_by) references user (id)
Hibernate: alter table user add constraint FK2a54xhceitopkkw1hlo3tkv3i foreign key (updated_by) references user (id)
2020-01-29 20:17:20.631  INFO 15012 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-01-29 20:17:20.637  INFO 15012 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-01-29 20:17:21.434  WARN 15012 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2020-01-29 20:17:21.738  INFO 15012 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-01-29 20:17:22.215  INFO 15012 --- [           main] com.metho.builder.entities.UserTest      : Started UserTest in 4.743 seconds (JVM running for 6.034)
[ConstraintViolationImpl{interpolatedMessage='Email should be valid', propertyPath=email, rootBeanClass=class com.metho.builder.entities.User, messageTemplate='Email should be valid'}]
2020-01-29 20:17:22.588  INFO 15012 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2020-01-29 20:17:22.589  INFO 15012 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-01-29 20:17:22.592  INFO 15012 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-01-29 20:17:22.667  INFO 15012 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
 

httpdigest

Top Contributor
Was ich jetzt erwartet hätte das er mir sysout in der Konsole ausgibt. Dieses passiert aber nicht.
Du meinst diese Zeile in deinen gezeigten Logs?
Code:
2020-01-29 20:17:22.215  INFO 15012 ...
[ConstraintViolationImpl{interpolatedMessage='Email should be valid', propertyPath=email, rootBeanClass=class com.metho.builder.entities.User, messageTemplate='Email should be valid'}]
 
K

kneitzel

Gast
Ja, der Code zeigt das auch recht deutlich - die Bezeichnungen stimmen sogar mehr oder weniger 1:1 ... und die Länge des "local part" ist 64 (Hier im Code ist die Länge 228) ... somit haben wir RFC und Quellcode des Validators schön im Einklang.
 

mrBrown

Super-Moderator
Mitarbeiter
Schreibt Ihr eure Unit-Tests ohne Logging? Ich schreibe in meine Tests auch immer einfache log Anweisungen um dann z.B. nicht nur ein "AssertionFailedError" zu sehen sondern halt auch Details. Sprich: Ich hätte hier auch die Violation ins Log geschrieben und beim failed Test hätte ich dann direkt gesehen, was denn angemeckert worden ist....

Jede vernünftige Assertions-Lib würde da auch was vernünftiges ausgeben, asssertTrue & asssertFalse sind halt einfach nur sehr sinnlos.

Irgendetwas, was Loggen könnte, gibts ja hier außer dem Test selbst nicht.
 
K

kneitzel

Gast
Jede vernünftige Assertions-Lib würde da auch was vernünftiges ausgeben, asssertTrue & asssertFalse sind halt einfach nur sehr sinnlos.

Irgendetwas, was Loggen könnte, gibts ja hier außer dem Test selbst nicht.
Ja, ich habe da auch noch etwas drüber nachgedacht. Bei unserem Code ist es auch tatsächlich so, dass das Logging in erster Linie im zu testenden Code sind. Da haben wir halt ein recht weitgehendes Logging bis ins Tracing hinein. (Produkte werden halt in Anlagen eingesetzt, wo man (wir) nicht mit dem Debugger drauf kann und so. Da ist ein gutes Traces extrem wichtig für unsere Supportleistung.

Daher ist das fehlende Logging hier auch eher darauf hinaus zu führen, dass hier eigentlich kein eigener Code sondern eben der Validation Code von der Library getestet wird.

Oder sehe ich das jetzt falsch?
 

mrBrown

Super-Moderator
Mitarbeiter
Daher ist das fehlende Logging hier auch eher darauf hinaus zu führen, dass hier eigentlich kein eigener Code sondern eben der Validation Code von der Library getestet wird.

Oder sehe ich das jetzt falsch?
Jein, es wird ja auch die richtige Annotation der Klasse getestet. Fände ich in dem Sinne durchaus auch einen sinnvollen Test.
 

TM69

Bekanntes Mitglied
Ich habe es jetzt nochmal abgeändert:
Code:
    /**
     * test user with email length 255
     */
    @Test
    void testUserWithEmailLength255MustBeTrue() {
        User user = new User();

        String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(186) + ".com";
        assertTrue(email.length() == 255, "Email is: " + email);

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail(email);
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        System.out.println(violations);
        assertTrue(violations.isEmpty(), email);
    }

@JustNobody:
Danke! Habs mir durchgelesen

@httpdigest:
Danke! Hab mir diese und https://github.com/hibernate/hibern...e/validator/internal/util/DomainNameUtil.java angesehen. Auch hier steht es so wie von @JustNobody angegebene Quelle.

Troztdem funktioniert es noch nicht. Immer noch den selben Fehler o_O


org.opentest4j.AssertionFailedError: UUYBBCJplzaOihPUFasUdfSvXZhzeKpZHHoRzHZldEDQcLoRLfjjLikhZHOvgozK@bfVenOXIPWQVJGTZsYBzTArCkGHKkSCIzNmutgrVHLxwSoVJDQirVAnZdLClgZgWhtnWcQaejizbWkAdTRxqSrxgNKwkMxDSxZnsCFmxtVTlcIAjmTZJLNXHRyruMyOXbUcPlXOoTdtCSvICXOKQMjvIUPApeGIjZbxkPzTcdwZmxgmLjOHeErdBgx.com ==> expected: <true> but was: <false>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:38)
at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:40)
at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:168)
at com.metho.builder.entities.UserTest.testUserWithEmailLength255MustBeTrue(UserTest.java:297)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:532)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:171)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:167)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:114)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:59)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:108)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
 

mrBrown

Super-Moderator
Mitarbeiter
Danke! Hab mir diese und https://github.com/hibernate/hibern...e/validator/internal/util/DomainNameUtil.java angesehen. Auch hier steht es so wie von @JustNobody angegebene Quelle.

Troztdem funktioniert es noch nicht. Immer noch den selben Fehler o_O
But be aware that each label (parts separated by a dot) of the domain name must be at most 63 characters long.

 

TM69

Bekanntes Mitglied
Auch mit 63 Stellen anstelle von 64:
Code:
    /**
     * test user with email length 255
     */
    @Test
    void testUserWithEmailLength255MustBeTrue() {
        User user = new User();

        String email = RandomStringUtils.randomAlphabetic(63) + "@" + RandomStringUtils.randomAlphabetic(187) + ".com";
        assertTrue(email.length() == 255, "Email is: " + email);

        user.setFirstname("firstname");
        user.setLastname("lastname");
        user.setEmail(email);
        user.setPassword("password");

        Set<ConstraintViolation<User>> violations = validator.validate(user);
        System.out.println(violations);
        assertTrue(violations.isEmpty(), email);
    }
 

mrBrown

Super-Moderator
Mitarbeiter
Es geht um den Teil hinterm '@' ;)


Warum denn überhaupt eine Zufällige Email? Zufall macht's in solchen Test doch eigentlich immer nur komplizierter
 

TM69

Bekanntes Mitglied
Es geht um den Teil hinterm '@' ;)


Warum denn überhaupt eine Zufällige Email? Zufall macht's in solchen Test doch eigentlich immer nur komplizierter
lt. Definition kann eine Email 64 Characters vor dem "@" haben und als Domain 255. s. @JustNobody Link. Deshalb wäre es ja eigentlich egal ob man sich einen Random - String erstellt und den verwendet oder fest angibst.
Deshalb verstehe ich deine Frage gerad nicht ob es um den hintern Teil geht.
 

mrBrown

Super-Moderator
Mitarbeiter
lt. Definition kann eine Email 64 Characters vor dem "@" haben und als Domain 255. s. @JustNobody Link. Deshalb wäre es ja eigentlich egal ob man sich einen Random - String erstellt und den verwendet oder fest angibst.
Deshalb verstehe ich deine Frage gerad nicht ob es um den hintern Teil geht.

Die Domain darf insgesamt 255 Zeichen haben, die einzelnen, durch '.' getrennten Teile der Domain aber jeweils nur 63.


Die Hinwies zum Zufall bezog sich generell auf die Tests, nicht auf die Länge der Email. Mit dem Zufall gewinnt man da nichts, verliert aber im Zweifelsfall Reproduzierbarkeit - mMn für solche Tests mit das wichtigste.
 

TM69

Bekanntes Mitglied
Ich habe es nochmal mit unterschiedlichen Werten probiert:
Code:
        String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(63) + ".com";
funktioniert.

Code:
        String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(64) + ".com";
Code:
ergibt (bei einem mehr in der Domain) einen Validation Error
 

mrBrown

Super-Moderator
Mitarbeiter
Eben nicht. Denn anscheinend mehr als 63 Zeichen in der Domain sind anscheinend nicht erlaubt. Wenn ich es die Quellenangabe von @JustNobody richtig verstehe, sind erlaubt:

  • 64 Zeichen vor dem "@"
  • und 255 Zeichen als Domain
und nicht max 63 für Domain.
Eben doch.

255 Zeichen darf die ganze Domain lang sein.
63 Zeichen darf jeder Part lang sein.

In deinem erfolgreichen Test: ganze Domain: 67 Zeichen, zwei Parts mit 63 bzw 3 Zeichen
In deinem fehlschlagenden Test: ganze Domain: 68 Zeichen, zwei Parts mit 64 bzw 3 Zeichen
 

mihe7

Top Contributor
Denn anscheinend mehr als 63 Zeichen in der Domain sind anscheinend nicht erlaubt.
Java:
RandomStringUtils.randomAlphabetic(63) + ".com";
Das sind bei mir 67 Zeichen - und die haben doch funktioniert.

EDIT: @mrBrown war schneller. Im Moment ist das Forum aber sehr lahm, vermutlich läuft um 00:00 Uhr die Sicherung an.
 

TM69

Bekanntes Mitglied
Entweder ist es jetzt zu spät :D Oder ich verstehe kein Englisch mehr :D
In addition to restrictions on syntax, there is a length limit on
email addresses. That limit is a maximum of 64 characters (octets)
in the "local part" (before the "@") and a maximum of 255 characters
(octets) in the domain part (after the "@") for a total length of 320
characters. Systems that handle email should be prepared to process
addresses which are that long, even though they are rarely
encountered.
https://tools.ietf.org/html/rfc3696#section-3

so ist es auch in
Code:
public class AbstractEmailValidator<A extends Annotation> implements ConstraintValidator<A, CharSequence> {

    private static final int MAX_LOCAL_PART_LENGTH = 64;
    ...
https://github.com/hibernate/hibern...intvalidators/AbstractEmailValidator.java#L35

und in
Code:
public final class DomainNameUtil {

    /**
     * This is the maximum length of a domain name. But be aware that each label (parts separated by a dot) of the
     * domain name must be at most 63 characters long. This is verified by {@link IDN#toASCII(String)}.
     */
    private static final int MAX_DOMAIN_PART_LENGTH = 255;
https://github.com/hibernate/hibern...intvalidators/AbstractEmailValidator.java#L35

@mrBrown und @mihe7: Deshalb verstehe ich nicht wie ihr auf 64 (nicht 63) für Localpart und MAX_DOMAIN_PART_LENGTH darf 255 sein.

Deshalb würde
Code:
 String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(63) + ".com";
wegen 64 Characters im Local Part fehlschlagen. Dieses ist aber nicht der Fall.
im Gegensatz müsste eine maximale Domain länge von >63 erlaubt sein. Dieses ist in

Code:
String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(64) + ".com";
Dieses stößt allerdings auf einen Validation Error.
 

mrBrown

Super-Moderator
Mitarbeiter
Localpart: Maximal 64 Zeichen. (MAX_LOCAL_PART_LENGTH = 64)
Gesamte Domain: 255 Zeichen. (MAX_DOMAIN_PART_LENGTH = 255)
Jeder Part der Domain: Maximal 63 Zeichen. (Javadoc über MAX_DOMAIN_PART_LENGTH = 255: "But be aware that each label (parts separated by a dot) of the domain name must be at most 63 characters long.")

Code:
localpart@domainlabel.domainlabel.domainlabel
^--64---^ ^---63----^ ^---63----^ ^---63----^
          ^---------------255---------------^

Deshalb würde
Code:
 String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(63) + ".com";
wegen 64 Characters im Local Part fehlschlagen. Dieses ist aber nicht der Fall.
64 Zeichen im Local-Part sind Okay.

im Gegensatz müsste eine maximale Domain länge von >63 erlaubt sein. Dieses ist in

Code:
String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(64) + ".com";
Dieses stößt allerdings auf einen Validation Error.

Die Domain ist 68 Zeichen lang, allerdings ist das erste Label/der erste Part der Domain 64 Zeichen lang, darf aber nur 63 lang sein.
 

TM69

Bekanntes Mitglied
Localpart: Maximal 64 Zeichen. (MAX_LOCAL_PART_LENGTH = 64)
Gesamte Domain: 255 Zeichen. (MAX_DOMAIN_PART_LENGTH = 255)
Jeder Part der Domain: Maximal 63 Zeichen. (Javadoc über MAX_DOMAIN_PART_LENGTH = 255: "But be aware that each label (parts separated by a dot) of the domain name must be at most 63 characters long.")

Code:
localpart@domainlabel.domainlabel.domainlabel
^--64---^ ^---63----^ ^---63----^ ^---63----^
          ^---------------255---------------^


64 Zeichen im Local-Part sind Okay.



Die Domain ist 68 Zeichen lang, allerdings ist das erste Label/der erste Part der Domain 64 Zeichen lang, darf aber nur 63 lang sein.
Eben nicht, weil dann müsste
Code:
String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(63) + ".com";
lt. deiner Aussage auf eine ValidationException stoßen.
Diese Zeile meldet beim Test allerdings keine ValidationException und der Test wird als erfolgreich abgesegnet.
 

mrBrown

Super-Moderator
Mitarbeiter
Wie lang sind denn deiner Meinung nach die einzelnen Elemente in der email-Adresse, und weshalb sollte die Validieren scheitern?
 

mrBrown

Super-Moderator
Mitarbeiter
Wo zählst du denn hier: RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(63) + ".com"; 255 Zeichen im Domain-Part? o_O
 

TM69

Bekanntes Mitglied
Wo zählst du denn hier: RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(63) + ".com"; 255 Zeichen im Domain-Part? o_O
Das ist korrekt. Es sind im Domain-Part nur 63 Zeichen. Allerdings bei einem 1 Zeichen mehr im Domain-Teil (s. #32)
Code:
String email = RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(64) + ".com";
wird eine ValidationException geworfen. Der Test ist nicht bestanden. Und dieses Verstehe ich jetzt nicht.
 

mrBrown

Super-Moderator
Mitarbeiter
Die Adresse besteht aus dem Localpart und der Domain. Der Localpart vor dem '@', die Domain hinter dem '@'
Die ganze Domain besteht aus mehreren Labeln. Die einzelnen Label werden dabei mit Punkten voneinander getrennt.
foo@bar.ba besteht zB aus dem Localpart foo (3 Zeichen) und der Domain bar.ba (6 Zeichen), diese wiederum besteht aus den Labeln bar (3 Z.) und ba (2 Z.).

Der Localpart darf 64 Zeichen lang sein.
Die Domain 255 Zeichen.
Jedes Label/jeder Part der Domain jeweils 63 Zeichen.


In deinem Beispiel RandomStringUtils.randomAlphabetic(64) + "@" + RandomStringUtils.randomAlphabetic(64) + ".com":
  • Localpart: RandomStringUtils.randomAlphabetic(64) => 64 Zeichen, also Okay
  • Domain: RandomStringUtils.randomAlphabetic(64) + ".com" => 68 Zeichen, also Okay
    • Erstes Domain-Label: RandomStringUtils.randomAlphabetic(64) => 64 Zeichen, nicht Okay
    • Zweites Domain-Label: com => 3 Zeichen, Okay
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
L Input/Output Email mit großer Pdf Anhang auslesen? Allgemeine Java-Themen 3
javaBoon86 Email Server Connection Problem Allgemeine Java-Themen 1
TimEtech Email senden - web.de ; Fehlercode Allgemeine Java-Themen 2
OnDemand Java Email Templates Allgemeine Java-Themen 2
B Java Mail: Prüfen, ob Email hat ein Anhang oder nicht Allgemeine Java-Themen 2
B Java Mail: Unterscheidung bei Attachments und eingefügte Bilder in Email Allgemeine Java-Themen 18
V EMail, Attachments auslesen von einer Email Allgemeine Java-Themen 0
B Bei Email: FW / AW... - Hilfe bei String suche Allgemeine Java-Themen 21
S Validation Null aber nicht Blank und muss Email sein Allgemeine Java-Themen 22
C Email Versand überprüfen Allgemeine Java-Themen 1
C Email mit public-key verschlüsseln Allgemeine Java-Themen 0
D Best Practice Gesamten Bildschirminhalt auslesen und Email schicken sobald kein Pixel sich ändert Allgemeine Java-Themen 11
M Email-Versand Java+Outlook Allgemeine Java-Themen 8
T Email versenden Allgemeine Java-Themen 1
P "Email" versenden mit Anhang Allgemeine Java-Themen 5
F JavaMail - Lokale eMail-Datei einlesen und parsen? Allgemeine Java-Themen 9
A Email-Programm aus Applet öffnen Allgemeine Java-Themen 4
A Email versenden mehrere Zeilen Allgemeine Java-Themen 10
H RegEX und eMail Allgemeine Java-Themen 4
foobar Email mit Standard Mailclient versenden Allgemeine Java-Themen 12
Developer_X Email per Java senden Allgemeine Java-Themen 81
D Email versand bei einem festgelegten Datum Allgemeine Java-Themen 11
C automatische email nach 6 tagen! Allgemeine Java-Themen 14
D Email an mehrer Absender versenden Allgemeine Java-Themen 3
M Email - Informationen auslesen Allgemeine Java-Themen 3
N EMail-Versandt mit Java 6: komplexer Body Allgemeine Java-Themen 4
M kennt jemand nen gute email client in java mit imap? Allgemeine Java-Themen 3
L javaformular auf website (eingabe per email zusenden) Allgemeine Java-Themen 3
L Java & Excel & EMail Allgemeine Java-Themen 2
L Ping Probe auf hinteren Teil einer Email Adresse (nach @) Allgemeine Java-Themen 5
G EMail Client Allgemeine Java-Themen 7
K Email mit Anhang über mailto:. versenden Allgemeine Java-Themen 11
S eMail Dienst mit Java Allgemeine Java-Themen 3
A Regulärer Ausdruck EMail-Prüfung Allgemeine Java-Themen 3
S java mail API, email versenden Allgemeine Java-Themen 8
S standard-email-programm öffnen Allgemeine Java-Themen 4

Ähnliche Java Themen

Neue Themen


Oben