Вот предложение, как вы могли бы сделать это.
Моделируйте каждое поле как отдельный класс, реализуя общий интерфейс Field
.
Внедрите все известные поля через конструктор и когдадля каждой записи ищите соответствующий класс поля для обработки проверки и обновления.
При таком подходе вы можете проверить логику проверки и обновления каждого поля отдельно.Добавление полей пользователя не увеличит ваш класс обслуживания.Тестирование PersonUpdateService должно будет использовать только одно или два проверенных поля для проверки логики поиска и выполнения.Хорошее разделение проблем, я бы сказал.
import java.util.*;
@Component
public class PersonUpdateService {
private final List<Field> fields;
@Autowired
public PersonUpdateService(final List<Field> fields) {
this.fields = fields;
}
public void updatePerson(final Person person, final Map<String, String> update) {
final boolean updated = false;
update.forEach((key, value) -> this.findField(key).update(person, value));
}
private Field findField(final String index) {
return this.fields.stream().filter(f -> f.index().equals(index)).findAny().orElseThrow(
() -> new IllegalArgumentException("Field not found: " + index));
}
}
Интерфейс поля:
public interface Field {
String index();
void update(Person person, String newValue);
}
Пример реализации поля:
import java.util.regex.Pattern;
@Component
public class NameField implements Field {
private static final String INDEX = "12";
private static final String REGEX = "/^[A-Z][a-z0-9_-]{1,19}$/";
private static final String CONSTRAINTS = "length min: 2, max: 20. First letter must uppercase";
@Override
public String index() {
return INDEX;
}
@Override
public void update(final Person person, final String newValue) {
if (!Pattern.matches(REGEX, newValue)) {
throw new ValidationException(CONSTRAINTS);
}
person.setName(newValue);
}
}
РЕДАКТИРОВАТЬ: добавлено @Компонент и аннотации @Autowired, чтобы указать, как внедрение зависимости может использоваться в Spring.Доступные компоненты, реализующие интерфейс Field, будут автоматически собраны Spring и введены через конструктор.В своем модульном тесте для сервиса вы можете ввести одно или два ложных поля.Не проверяйте фактическую логику проверки / обновления реализаций полей в сервисном тесте, но создавайте отдельные модульные тесты для каждого класса полей.
РЕДАКТИРОВАТЬ 2: приведенный выше совет по написанию модульных тестов взят из моего (mockist) перспектива.Классические юнит-тестеры, вероятно, написали бы один тест, чтобы охватить все спецификации (как тест, который вы предоставили в посте).Причина, по которой я не предпочитаю, заключается в том, что пограничные случаи легче теряются в таком модульном тесте в стиле интеграции, и увеличивается вероятность того, что вы делаете ложные предположения о том, как работает код, или что вам приходится многократно использовать один и тот же код в вашемтесты.Однако это давняя дискуссия, и существует множество точек зрения, которые имеют свои достоинства.