@Email

Diskutiere @Email im Allgemeine Java-Themen Bereich.

Bitte aktiviere JavaScript!
T

TM69

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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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 protected]");
        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.
 
H

httpdigest

Nicht jeder Random String, der ein @ Zeichen irgendwo hat und ein "." irgendwo hinten, ist eine gültige E-Mail Adresse. Mit welchen Random Strings schlägt denn dein Test fehl? Hast du das mal geprüft?
Zum Beispiel sind zwei hintereinanderfolgende Punkte ungültig.
Vermutlich implementiert der Validation Provider: https://tools.ietf.org/html/rfc5322#section-3.4.1
 
J

JustNobody

Ä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!
 
T

TM69

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>
 
J

JustNobody

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.
 
T

TM69

Ä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
 
H

httpdigest

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?
 
T

TM69

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:
H

httpdigest

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);
 
J

JustNobody

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.
 
T

TM69

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.
 
H

httpdigest

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'}]
 
J

JustNobody

M

mrBrown

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.
 
J

JustNobody

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?
 
M

mrBrown

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.
 
T

TM69

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/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/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: U[email protected]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)
 
M

mrBrown

Danke! Hab mir diese und https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/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.
 
T

TM69

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);
    }
 
M

mrBrown

Es geht um den Teil hinterm '@' ;)


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

TM69

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.
 
M

mrBrown

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.
 
T

TM69

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
 
M

mrBrown

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

mihe7

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.
 
T

TM69

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/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/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/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/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.
 
M

mrBrown

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:
[email protected]
^--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.
 
T

TM69

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:
[email protected]
^--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.
 
M

mrBrown

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

mrBrown

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

TM69

Wie ist es sonst auch zuerklären das der Part-Teil mit 64 (s. Code oben) als korrekt abgezeichnet wird?
 
T

TM69

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.
 
M

mrBrown

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.
[email protected] 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
 
Thema: 

@Email

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben