数据验证:另一种方法

检查用户输入的应用程序中的数据或以传统方式以其他方式获得的数据意味着在代码中仅使用两个表达式:TRUE和FALSE。在另一个实施例中,使用了显然不是为此目的的例外。有更好的选择吗?

验证由所谓的“ 验证器”完成(这只是整个数据验证过程的一部分)。文章用户数据的服务器验证提供了验证器实现的一个有趣的版本,但也有在形成几个细微之处消息本地化错误格式本身

首先考虑错误格式。

提议的方法是针对验证器方法,该方法检查数据以返回字符串集合(数组,列表等),而不是布尔值或引发异常。这样的格式将更加灵活和有用。

我将用Java举例:

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

如您所见,所有方法都返回字符串的集合。

单元测试示例:

        @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());
	}

现在考虑错误消息的本地化。

再次以Java为例:

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

本地化文件位于src / main /资源中。

errors_ru.properties:

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

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

我希望其他用自己的语言编写的程序员会发现这种方法既实用又方便,并且能够在家中应用它。

PS

用户身份验证方法的一种变体,它返回java.util.Map.Entry <K,V>接口实现,并且可以将用户对象错误数据都包含为字符串(此方法也可以用来避免从当需要用户对象时的方法):

@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());
		}
	}
}

当然,在中心上一篇关于Java验证的精彩文章,但是在那里提出的方法可以在所有情况下使用,并且基于注释和异常。

在文章的结尾,有几个关于测试的有用链接:

  1. 软件测试的反模式
  2. 汽车测试概念

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


All Articles