Validasi Data: Suatu Pendekatan Yang Berbeda

Memeriksa data dalam aplikasi yang dimasukkan oleh pengguna atau diperoleh dengan cara lain dalam arti klasik menyiratkan penggunaan hanya dua ekspresi dalam kode: BENAR dan SALAH. Dalam perwujudan lain, pengecualian digunakan yang jelas tidak dimaksudkan untuk ini. Apakah ada opsi yang lebih baik?

Validasi dilakukan oleh yang disebut Validator (yang hanya bagian dari keseluruhan proses validasi data). Artikel Server Validasi Data Pengguna menyediakan versi yang menarik dari implementasi validator, tetapi ada beberapa nuansa dalam bentuk lokalisasi pesan dan format kesalahan itu sendiri .

Pertimbangkan format kesalahan terlebih dahulu.

Pendekatan yang diusulkan adalah untuk metode validator yang memeriksa data untuk mengembalikan koleksi (array, daftar, dll.) String, bukan nilai boolean atau melemparkan pengecualian. Format seperti itu akan lebih fleksibel dan informatif.

Saya akan memberikan contoh di Jawa:

import java.util.ArrayList;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public interface ValidateUser {
	String OK = "OK:";
	String FAIL= "FAIL:";
	Collection<String> apply(String username, String password, String email);
	default Collection<String> passwordValidate(String password){
		var result = new ArrayList<String>(1);
		int size = password.trim().length();
		if(size < 3 || size > 20) result.add("Password error:too short value or too long name. Password must be greater or 3 characters and smaller then 20 simbols.");
		return result;
	}
	default Collection<String> usernameValidate(String name){
		var result = new ArrayList<String>(1);
		int size = name.trim().length();
		if(size < 3 || size > 30) result.add("Username error:too short or too long name. Name must be greater or 3 characters and smaller then 30 simbols.");
		return result;
	}
	default Collection<String> emailValidate(String email){
		var result = new ArrayList<String>(1);
		String regex = "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(email);
		if (!matcher.find()) result.add("Email error:" + email + " is not valid");
		return result;
	}
	class Default implements ValidateUser{

		@Override
		public Collection<String> apply(String username, String password,
				String email) {
			var errors = passwordValidate(password.trim());
			errors.addAll(usernameValidate(username.trim()));
			errors.addAll(emailValidate(email.trim()));
			return errors;
		}
		
	}
}

Seperti yang Anda lihat di sini, semua metode mengembalikan koleksi string.

Contoh pengujian unit:

        @Test
	void validateUserTest() {
		
		var validate = new ValidateUser2.Default();
		var result = validate.apply("aaa", "qwe", "aaa@mail.ru");
		assertTrue(result.isEmpty());
		result = validate.apply("aaa", "qwe", "");
		assertFalse(result.isEmpty());
		assertEquals(1, result.size());
		
		result = validate.apply("aa", "qwe", "aaa@mail.ru");
		assertFalse(result.isEmpty());
		assertEquals(1, result.size());
		
		result = validate.apply("aaa", "qwe", "@mail.qweqwe");
		assertFalse(result.isEmpty());
		assertEquals(1, result.size());
		
		result = validate.apply("aa", "qw", "");
		assertFalse(result.isEmpty());
		assertEquals(3, result.size());
	}

Sekarang pertimbangkan lokalisasi pesan kesalahan.

Contoh lagi di Jawa:

public interface LocalizedValidation {
	String OK = "OK:";
	String FAIL= "FAIL:";
	Collection<String> apply(String username, String password, String email, Locale locale);
	default Collection<String> passwordValidate(String password, ResourceBundle bundle){
		var result = new ArrayList<String>(1);
		int size = password.trim().length();
		if(size < 3 || size > 20) result.add(bundle.getString("password"));
		return result;
	}
	default Collection<String> usernameValidate(String name, ResourceBundle bundle){
		var result = new ArrayList<String>(1);
		int size = name.trim().length();
		if(size < 3 || size > 30) result.add(bundle.getString("username"));
		return result;
	}
	default Collection<String> emailValidate(String email, ResourceBundle bundle){
		var result = new ArrayList<String>(1);
		String regex = "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(email);
		if (!matcher.find()) result.add(bundle.getString("username")+email);
		return result;
	}
	class Default implements LocalizedValidation{

		@Override
		public Collection<String> apply(String username, String password,
				String email, Locale locale) {
			ResourceBundle bundle = ResourceBundle.getBundle("errors", locale);
			var errors = passwordValidate(password.trim(), bundle);
			errors.addAll(usernameValidate(username.trim(), bundle));
			errors.addAll(emailValidate(email.trim(), bundle));
			return errors;
		}
	}
}


	@Test
	void localizedUserTest() {
		var validate = new LocalizedValidation.Default();
		var result = validate.apply("aaa", "qwe", "aaa@mail.ru", Locale.ENGLISH);
		assertTrue(result.isEmpty());
		result = validate.apply("aaa", "qwe", "", Locale.ENGLISH);
		assertFalse(result.isEmpty());
		assertEquals(1, result.size());
		System.out.println(result.iterator().next());
		
		result = validate.apply("aaa", "qwe", "", new Locale("ru"));
		assertFalse(result.isEmpty());
		assertEquals(1, result.size());
		System.out.println(result.iterator().next());
	}

File lokalisasi ada di src / main / resource.

errors_ru.properties:

mail=Email :   Email:
username=  :     .
password=   :   .

properties.properties:

mail=Email error: is not valid:
username=Username error:too short or too long name. Name must be greater or 3 characters and smaller then 30 simbols.
password=Password error:too short value or too long name. Password must be greater or 3 characters and smaller then 20 simbols.

Saya berharap bahwa pemrogram lain yang menulis dalam bahasa mereka sendiri akan menemukan pendekatan ini praktis dan nyaman dan dapat menerapkannya di rumah.

PS

Varian dari metode otentikasi pengguna yang mengembalikan implementasi antarmuka java.util.Map.Entry <K, V> dan dapat berisi objek pengguna dan data kesalahan sebagai string (pendekatan ini juga dapat digunakan untuk menghindari pengembalian Null dari metode saat objek pengguna diharapkan):

@Override
public Entry<String, User> auth(String username, String password, String email) {
	var errors = passwordValidation.apply(password.trim());
	errors.addAll(userNameValidation.apply(username.trim()));
	errors.addAll(emailValidation.apply(email.trim()));
	if(!errors.isEmpty()) {
		return REntry.ofI(null, errors.stream().collect(Collectors.joining(";")));
	}else {
		try {
			var passwordEncrypted = new Encrypt().apply(password.trim());
			var user = new User.Default(0L, username.trim(), email.trim(), passwordEncrypted, "").create(dataSource);
			return REntry.ofI(user, "user is null!");
		} catch (RuntimeException e) {
			return REntry.ofI(null, e.getMessage());
		}
	}
}

Tentu saja, ada artikel yang bagus di hub tentang validasi di Jawa , tetapi pendekatan yang disarankan di sana dapat digunakan jauh dari semua kasus dan didasarkan pada anotasi dan pengecualian.

Di akhir artikel, beberapa tautan bermanfaat tentang pengujian:

  1. Antipatterns pengujian perangkat lunak
  2. Konsep Pengujian Otomatis

Source: https://habr.com/ru/post/undefined/


All Articles