-
Notifications
You must be signed in to change notification settings - Fork 3
Lesson 125-127 (JUnit/Mockito) #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: mockito-for-pr
Are you sure you want to change the base?
Changes from 14 commits
74f800c
14ac90a
b607151
c4976ff
cc53241
bb7b651
b732195
f435117
b8ded7f
64b9d80
b68f560
724fc51
78e5bed
a8ff859
516bc6d
dae78a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| #Tue Feb 11 23:22:06 MSK 2025 | ||
| distributionBase=GRADLE_USER_HOME | ||
| distributionPath=wrapper/dists | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip | ||
| zipStoreBase=GRADLE_USER_HOME | ||
| zipStorePath=wrapper/dists |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| rootProject.name = 'unit-testing-practical-task' | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,77 +1,12 @@ | ||
| package com.walking.lesson125_unit_testing; | ||
|
|
||
|
|
||
| import com.walking.lesson125_unit_testing.exception.RegexValidationException; | ||
| import com.walking.lesson125_unit_testing.model.FullName; | ||
|
|
||
| /** | ||
| * На базе вашего решения | ||
| * <a href="https://github.com/KFalcon2022/unit-testing-practical-task">задачи из урока 125</a> | ||
| * актуализируйте юнит-тесты с использованием Mockito. Сложность задачи напрямую зависит от качества декомпозиции в | ||
| * вашем предыдущем решении. | ||
| */ | ||
| public class Main { | ||
|
|
||
| public static final String FULL_NAME_REGEX = "^[А-Я][А-Яа-я-]* [А-Я][а-я]* [А-Я][а-я]+$"; | ||
| public static final String DOUBLE_SURNAME_REGEX = "[А-Я][а-я]*-[А-Я][а-я]*"; | ||
| public static final String NAME_REGEX = "[А-Я][а-я]*"; | ||
| public static final String PATRONYMIC_REGEX = "[А-Я][а-я]+"; | ||
|
|
||
| public static void main(String[] args) { | ||
| System.out.println(parseName("Иванов Иван Иванович")); | ||
| System.out.println(parseName("Иванов-Иванов Иван Иванович")); | ||
| System.out.println(parseName("Иванов-Иванов И Иванович")); | ||
| System.out.println(parseName("И-Иванов И Иванович")); | ||
| System.out.println(parseName("Иванов иван Иванович")); | ||
| // Все равно упадет на 30й строке. | ||
| // System.out.println(parseName("И-иванов И Иванович")); | ||
| // System.out.println(parseName("Иванов Иван иванович")); | ||
| // System.out.println(parseName("ИваНов Иван Иванович")); | ||
| // System.out.println(parseName("Ivanov Ivan")); | ||
| } | ||
|
|
||
| private static FullName parseName(String nameString) { | ||
| if (!nameString.matches(FULL_NAME_REGEX)) { | ||
| throw new RegexValidationException(nameString, FULL_NAME_REGEX); | ||
| } | ||
|
|
||
| FullName fullName = new FullName(); | ||
| String[] splitNameString = nameString.split(" "); | ||
|
|
||
| String surname = splitNameString[0]; | ||
| validateSurname(surname); | ||
| fullName.setSurname(surname); | ||
|
|
||
| String name = splitNameString[1]; | ||
| validateName(name); | ||
| fullName.setName(name); | ||
|
|
||
| String patronymic = splitNameString[2]; | ||
| validatePatronymic(patronymic); | ||
| fullName.setPatronymic(patronymic); | ||
|
|
||
| return fullName; | ||
| } | ||
|
|
||
| private static void validateSurname(String surname) { | ||
| if (surname.contains("-")) { | ||
| if (!surname.matches(DOUBLE_SURNAME_REGEX)) { | ||
| throw new RegexValidationException(surname, DOUBLE_SURNAME_REGEX); | ||
| } | ||
| } else { | ||
| validateName(surname); | ||
| } | ||
| } | ||
|
|
||
| private static void validateName(String name) { | ||
| if (!name.matches(NAME_REGEX)) { | ||
| throw new RegexValidationException(name, NAME_REGEX); | ||
| } | ||
| } | ||
|
|
||
| private static void validatePatronymic(String name) { | ||
| if (!name.matches(PATRONYMIC_REGEX)) { | ||
| throw new RegexValidationException(name, PATRONYMIC_REGEX); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| package com.walking.lesson125_unit_testing.model; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class FullName { | ||
| private String name; | ||
| private String surname; | ||
|
|
@@ -42,4 +44,26 @@ public void setPatronymic(String patronymic) { | |
| public String toString() { | ||
| return "%s %s %s".formatted(surname, name, patronymic); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) { | ||
| return true; | ||
| } | ||
| if (o == null || getClass() != o.getClass()) { | ||
| return false; | ||
| } | ||
|
|
||
| FullName fullName = (FullName) o; | ||
| return Objects.equals(name, fullName.name) && Objects.equals(surname, fullName.surname) && Objects.equals( | ||
| patronymic, fullName.patronymic); | ||
|
||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| int result = Objects.hashCode(name); | ||
| result = 31 * result + Objects.hashCode(surname); | ||
| result = 31 * result + Objects.hashCode(patronymic); | ||
| return result; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package com.walking.lesson125_unit_testing.service; | ||
|
|
||
| import com.walking.lesson125_unit_testing.exception.RegexValidationException; | ||
| import com.walking.lesson125_unit_testing.model.FullName; | ||
|
|
||
| public class FullNameParsingService { | ||
| private final FullNameValidationService fullNameValidationService; | ||
|
|
||
| public FullNameParsingService(FullNameValidationService fullNameValidationService) { | ||
| this.fullNameValidationService = fullNameValidationService; | ||
| } | ||
|
|
||
| public FullName parseFullName(String nameString) { | ||
| try { | ||
| fullNameValidationService.validateFullName(nameString); | ||
|
|
||
| String[] splitNameString = nameString.split(" "); | ||
|
|
||
| String surname = splitNameString[0]; | ||
| fullNameValidationService.validateSurname(surname); | ||
|
|
||
| String name = splitNameString[1]; | ||
| fullNameValidationService.validateName(name); | ||
|
|
||
| String patronymic = splitNameString[2]; | ||
| fullNameValidationService.validatePatronymic(patronymic); | ||
|
|
||
| return new FullName(name, surname, patronymic); | ||
| } catch (RegexValidationException e) { | ||
|
||
| throw new RuntimeException("Failed parsing fullName", e); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package com.walking.lesson125_unit_testing.service; | ||
|
|
||
| import com.walking.lesson125_unit_testing.exception.RegexValidationException; | ||
|
|
||
| public class FullNameValidationService { | ||
| public static final String FULL_NAME_REGEX = "^[А-Я][А-Яа-я-]* [А-Я][а-я]* [А-Я][а-я]+$"; | ||
| public static final String DOUBLE_SURNAME_REGEX = "[А-Я][а-я]*-[А-Я][а-я]*"; | ||
| public static final String NAME_REGEX = "[А-Я][а-я]*"; | ||
| public static final String PATRONYMIC_REGEX = "[А-Я][а-я]+"; | ||
|
||
|
|
||
| public FullNameValidationService() { | ||
|
||
| } | ||
|
|
||
| public void validateFullName(String nameString) { | ||
| if (!nameString.matches(FULL_NAME_REGEX)) { | ||
| throw new RegexValidationException(nameString, FULL_NAME_REGEX); | ||
| } | ||
| } | ||
|
|
||
| public void validateSurname(String surname) { | ||
| if (surname.contains("-")) { | ||
| if (!surname.matches(DOUBLE_SURNAME_REGEX)) { | ||
| throw new RegexValidationException(surname, DOUBLE_SURNAME_REGEX); | ||
| } | ||
| } else { | ||
| validateName(surname); | ||
| } | ||
| } | ||
|
|
||
| public void validateName(String name) { | ||
| if (!name.matches(NAME_REGEX)) { | ||
| throw new RegexValidationException(name, NAME_REGEX); | ||
| } | ||
| } | ||
|
|
||
| public void validatePatronymic(String name) { | ||
| if (!name.matches(PATRONYMIC_REGEX)) { | ||
| throw new RegexValidationException(name, PATRONYMIC_REGEX); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package com.walking.lesson125_unit_testing.service; | ||
|
|
||
| import com.walking.lesson125_unit_testing.exception.RegexValidationException; | ||
| import com.walking.lesson125_unit_testing.model.FullName; | ||
| import org.junit.jupiter.api.BeforeAll; | ||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.junit.jupiter.api.extension.ExtendWith; | ||
| import org.junit.jupiter.api.function.Executable; | ||
| import org.mockito.InjectMocks; | ||
| import org.mockito.Mock; | ||
| import org.mockito.Mockito; | ||
| import org.mockito.junit.jupiter.MockitoExtension; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| class FullNameParsingServiceTest { | ||
| @InjectMocks | ||
| private FullNameParsingService fullNameParsingService; | ||
|
|
||
| @Mock | ||
| private FullNameValidationService fullNameValidationService; | ||
|
|
||
| @Test | ||
| void parseFullName_success() { | ||
| // given | ||
| String testFullNameString = "Иванов Иван Иванович"; | ||
| FullName validFullName = new FullName("Иван", "Иванов", "Иванович"); | ||
| // when | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. пустая строка перед комментом. Логика простая: мы отделяем логические блоки кода пустой строкой. Коммент к строке кода или к блоку - часть этого блока |
||
| FullName parsedFullName = fullNameParsingService.parseFullName(testFullNameString); | ||
| // then | ||
| assertEquals(validFullName, parsedFullName); | ||
| } | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Опциональная рекомендация (здесь скорее не нужна): для однообразия тестов и более прозрачных инструкций можно явно прописывать конфигурацию мока на стандартное поведение (условно, В простых случаях, как здесь, это избыточно |
||
|
|
||
| @Test | ||
| void parseFullName_fail() { | ||
| // given | ||
| Mockito.doThrow(RegexValidationException.class) | ||
| .when(fullNameValidationService) | ||
| .validateFullName(Mockito.anyString()); | ||
| // when | ||
| Executable actual = () -> fullNameParsingService.parseFullName(Mockito.any()); | ||
| // then | ||
| assertThrows(RuntimeException.class, actual); | ||
| } | ||
| } | ||
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
лишняя пустая строка