mirror of
https://github.com/cna-bootcamp/lifesub.git
synced 2026-06-12 20:49:09 +00:00
add testcode
This commit is contained in:
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+110
@@ -0,0 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
|
||||
<title>Test results - CustomUserDetailsServiceTest</title>
|
||||
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="../js/report.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<h1>CustomUserDetailsServiceTest</h1>
|
||||
<div class="breadcrumbs">
|
||||
<a href="../index.html">all</a> >
|
||||
<a href="../packages/com.unicorn.lifesub.member.test.unit.config.jwt.html">com.unicorn.lifesub.member.test.unit.config.jwt</a> > CustomUserDetailsServiceTest</div>
|
||||
<div id="summary">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="summaryGroup">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="infoBox" id="tests">
|
||||
<div class="counter">3</div>
|
||||
<p>tests</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="failures">
|
||||
<div class="counter">0</div>
|
||||
<p>failures</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="ignored">
|
||||
<div class="counter">0</div>
|
||||
<p>ignored</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="duration">
|
||||
<div class="counter">1.064s</div>
|
||||
<p>duration</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox success" id="successRate">
|
||||
<div class="percent">100%</div>
|
||||
<p>successful</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="tabs">
|
||||
<ul class="tabLinks">
|
||||
<li>
|
||||
<a href="#tab0">Tests</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="tab0" class="tab">
|
||||
<h2>Tests</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Test</th>
|
||||
<th>Method name</th>
|
||||
<th>Duration</th>
|
||||
<th>Result</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="success">givenExistingUserId_whenLoadUser_thenReturnUserDetails</td>
|
||||
<td class="success">givenExistingUserId_whenLoadUser_thenReturnUserDetails()</td>
|
||||
<td class="success">0.008s</td>
|
||||
<td class="success">passed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="success">givenNonExistentUserId_whenLoadUser_thenThrowException</td>
|
||||
<td class="success">givenNonExistentUserId_whenLoadUser_thenThrowException()</td>
|
||||
<td class="success">0.864s</td>
|
||||
<td class="success">passed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="success">givenUserWithRoles_whenLoadUser_thenMapAuthoritiesCorrectly</td>
|
||||
<td class="success">givenUserWithRoles_whenLoadUser_thenMapAuthoritiesCorrectly()</td>
|
||||
<td class="success">0.192s</td>
|
||||
<td class="success">passed</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>
|
||||
<div>
|
||||
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
|
||||
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
|
||||
</label>
|
||||
</div>Generated by
|
||||
<a href="http://www.gradle.org">Gradle 8.4</a> at 2025. 2. 14. 오후 4:50:22</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,179 @@
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
body, a, a:visited {
|
||||
color: #303030;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding-left: 50px;
|
||||
padding-right: 50px;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
#content h1 {
|
||||
font-size: 160%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
margin-top: 100px;
|
||||
font-size: 80%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#footer, #footer a {
|
||||
color: #a0a0a0;
|
||||
}
|
||||
|
||||
#line-wrapping-toggle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#label-for-line-wrapping-toggle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
ul.tabLinks {
|
||||
padding-left: 0;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
overflow: auto;
|
||||
min-width: 800px;
|
||||
width: auto !important;
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
ul.tabLinks li {
|
||||
float: left;
|
||||
height: 100%;
|
||||
list-style: none;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
margin-bottom: 0;
|
||||
-moz-border-radius: 7px;
|
||||
border-radius: 7px;
|
||||
margin-right: 25px;
|
||||
border: solid 1px #d4d4d4;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
ul.tabLinks li:hover {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
ul.tabLinks li.selected {
|
||||
background-color: #c5f0f5;
|
||||
border-color: #c5f0f5;
|
||||
}
|
||||
|
||||
ul.tabLinks a {
|
||||
font-size: 120%;
|
||||
display: block;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.tabLinks li h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.tab {
|
||||
}
|
||||
|
||||
div.selected {
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.deselected {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.tab table {
|
||||
min-width: 350px;
|
||||
width: auto !important;
|
||||
width: 350px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
div.tab th, div.tab table {
|
||||
border-bottom: solid #d0d0d0 1px;
|
||||
}
|
||||
|
||||
div.tab th {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
padding-left: 6em;
|
||||
}
|
||||
|
||||
div.tab th:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
div.tab td {
|
||||
white-space: nowrap;
|
||||
padding-left: 6em;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
div.tab td:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
div.tab td.numeric, div.tab th.numeric {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
span.code {
|
||||
display: inline-block;
|
||||
margin-top: 0em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
span.code pre {
|
||||
font-size: 11pt;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
margin: 0;
|
||||
background-color: #f7f7f7;
|
||||
border: solid 1px #d0d0d0;
|
||||
min-width: 700px;
|
||||
width: auto !important;
|
||||
width: 700px;
|
||||
}
|
||||
|
||||
span.wrapped pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
label.hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
#summary {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
#summary table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#summary td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.breadcrumbs, .breadcrumbs a {
|
||||
color: #606060;
|
||||
}
|
||||
|
||||
.infoBox {
|
||||
width: 110px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.infoBox p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.counter, .percent {
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
#duration {
|
||||
width: 125px;
|
||||
}
|
||||
|
||||
#successRate, .summaryGroup {
|
||||
border: solid 2px #d0d0d0;
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#successRate {
|
||||
width: 140px;
|
||||
margin-left: 35px;
|
||||
}
|
||||
|
||||
#successRate .percent {
|
||||
font-size: 180%;
|
||||
}
|
||||
|
||||
.success, .success a {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
div.success, #successRate.success {
|
||||
background-color: #bbd9bb;
|
||||
border-color: #008000;
|
||||
}
|
||||
|
||||
.failures, .failures a {
|
||||
color: #b60808;
|
||||
}
|
||||
|
||||
.skipped, .skipped a {
|
||||
color: #c09853;
|
||||
}
|
||||
|
||||
div.failures, #successRate.failures {
|
||||
background-color: #ecdada;
|
||||
border-color: #b60808;
|
||||
}
|
||||
|
||||
ul.linkList {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
ul.linkList li {
|
||||
list-style: none;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
|
||||
<title>Test results - Test Summary</title>
|
||||
<link href="css/base-style.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="css/style.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="js/report.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<h1>Test Summary</h1>
|
||||
<div id="summary">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="summaryGroup">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="infoBox" id="tests">
|
||||
<div class="counter">3</div>
|
||||
<p>tests</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="failures">
|
||||
<div class="counter">0</div>
|
||||
<p>failures</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="ignored">
|
||||
<div class="counter">0</div>
|
||||
<p>ignored</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="duration">
|
||||
<div class="counter">1.064s</div>
|
||||
<p>duration</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox success" id="successRate">
|
||||
<div class="percent">100%</div>
|
||||
<p>successful</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="tabs">
|
||||
<ul class="tabLinks">
|
||||
<li>
|
||||
<a href="#tab0">Packages</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#tab1">Classes</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="tab0" class="tab">
|
||||
<h2>Packages</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Package</th>
|
||||
<th>Tests</th>
|
||||
<th>Failures</th>
|
||||
<th>Ignored</th>
|
||||
<th>Duration</th>
|
||||
<th>Success rate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="success">
|
||||
<a href="packages/com.unicorn.lifesub.member.test.unit.config.jwt.html">com.unicorn.lifesub.member.test.unit.config.jwt</a>
|
||||
</td>
|
||||
<td>3</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>1.064s</td>
|
||||
<td class="success">100%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="tab1" class="tab">
|
||||
<h2>Classes</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Class</th>
|
||||
<th>Tests</th>
|
||||
<th>Failures</th>
|
||||
<th>Ignored</th>
|
||||
<th>Duration</th>
|
||||
<th>Success rate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="success">
|
||||
<a href="classes/com.unicorn.lifesub.member.test.unit.config.jwt.CustomUserDetailsServiceTest.html">com.unicorn.lifesub.member.test.unit.config.jwt.CustomUserDetailsServiceTest</a>
|
||||
</td>
|
||||
<td>3</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>1.064s</td>
|
||||
<td class="success">100%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>
|
||||
<div>
|
||||
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
|
||||
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
|
||||
</label>
|
||||
</div>Generated by
|
||||
<a href="http://www.gradle.org">Gradle 8.4</a> at 2025. 2. 14. 오후 4:50:22</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,194 @@
|
||||
(function (window, document) {
|
||||
"use strict";
|
||||
|
||||
var tabs = {};
|
||||
|
||||
function changeElementClass(element, classValue) {
|
||||
if (element.getAttribute("className")) {
|
||||
element.setAttribute("className", classValue);
|
||||
} else {
|
||||
element.setAttribute("class", classValue);
|
||||
}
|
||||
}
|
||||
|
||||
function getClassAttribute(element) {
|
||||
if (element.getAttribute("className")) {
|
||||
return element.getAttribute("className");
|
||||
} else {
|
||||
return element.getAttribute("class");
|
||||
}
|
||||
}
|
||||
|
||||
function addClass(element, classValue) {
|
||||
changeElementClass(element, getClassAttribute(element) + " " + classValue);
|
||||
}
|
||||
|
||||
function removeClass(element, classValue) {
|
||||
changeElementClass(element, getClassAttribute(element).replace(classValue, ""));
|
||||
}
|
||||
|
||||
function initTabs() {
|
||||
var container = document.getElementById("tabs");
|
||||
|
||||
tabs.tabs = findTabs(container);
|
||||
tabs.titles = findTitles(tabs.tabs);
|
||||
tabs.headers = findHeaders(container);
|
||||
tabs.select = select;
|
||||
tabs.deselectAll = deselectAll;
|
||||
tabs.select(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getCheckBox() {
|
||||
return document.getElementById("line-wrapping-toggle");
|
||||
}
|
||||
|
||||
function getLabelForCheckBox() {
|
||||
return document.getElementById("label-for-line-wrapping-toggle");
|
||||
}
|
||||
|
||||
function findCodeBlocks() {
|
||||
var spans = document.getElementById("tabs").getElementsByTagName("span");
|
||||
var codeBlocks = [];
|
||||
for (var i = 0; i < spans.length; ++i) {
|
||||
if (spans[i].className.indexOf("code") >= 0) {
|
||||
codeBlocks.push(spans[i]);
|
||||
}
|
||||
}
|
||||
return codeBlocks;
|
||||
}
|
||||
|
||||
function forAllCodeBlocks(operation) {
|
||||
var codeBlocks = findCodeBlocks();
|
||||
|
||||
for (var i = 0; i < codeBlocks.length; ++i) {
|
||||
operation(codeBlocks[i], "wrapped");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleLineWrapping() {
|
||||
var checkBox = getCheckBox();
|
||||
|
||||
if (checkBox.checked) {
|
||||
forAllCodeBlocks(addClass);
|
||||
} else {
|
||||
forAllCodeBlocks(removeClass);
|
||||
}
|
||||
}
|
||||
|
||||
function initControls() {
|
||||
if (findCodeBlocks().length > 0) {
|
||||
var checkBox = getCheckBox();
|
||||
var label = getLabelForCheckBox();
|
||||
|
||||
checkBox.onclick = toggleLineWrapping;
|
||||
checkBox.checked = false;
|
||||
|
||||
removeClass(label, "hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function switchTab() {
|
||||
var id = this.id.substr(1);
|
||||
|
||||
for (var i = 0; i < tabs.tabs.length; i++) {
|
||||
if (tabs.tabs[i].id === id) {
|
||||
tabs.select(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function select(i) {
|
||||
this.deselectAll();
|
||||
|
||||
changeElementClass(this.tabs[i], "tab selected");
|
||||
changeElementClass(this.headers[i], "selected");
|
||||
|
||||
while (this.headers[i].firstChild) {
|
||||
this.headers[i].removeChild(this.headers[i].firstChild);
|
||||
}
|
||||
|
||||
var h2 = document.createElement("H2");
|
||||
|
||||
h2.appendChild(document.createTextNode(this.titles[i]));
|
||||
this.headers[i].appendChild(h2);
|
||||
}
|
||||
|
||||
function deselectAll() {
|
||||
for (var i = 0; i < this.tabs.length; i++) {
|
||||
changeElementClass(this.tabs[i], "tab deselected");
|
||||
changeElementClass(this.headers[i], "deselected");
|
||||
|
||||
while (this.headers[i].firstChild) {
|
||||
this.headers[i].removeChild(this.headers[i].firstChild);
|
||||
}
|
||||
|
||||
var a = document.createElement("A");
|
||||
|
||||
a.setAttribute("id", "ltab" + i);
|
||||
a.setAttribute("href", "#tab" + i);
|
||||
a.onclick = switchTab;
|
||||
a.appendChild(document.createTextNode(this.titles[i]));
|
||||
|
||||
this.headers[i].appendChild(a);
|
||||
}
|
||||
}
|
||||
|
||||
function findTabs(container) {
|
||||
return findChildElements(container, "DIV", "tab");
|
||||
}
|
||||
|
||||
function findHeaders(container) {
|
||||
var owner = findChildElements(container, "UL", "tabLinks");
|
||||
return findChildElements(owner[0], "LI", null);
|
||||
}
|
||||
|
||||
function findTitles(tabs) {
|
||||
var titles = [];
|
||||
|
||||
for (var i = 0; i < tabs.length; i++) {
|
||||
var tab = tabs[i];
|
||||
var header = findChildElements(tab, "H2", null)[0];
|
||||
|
||||
header.parentNode.removeChild(header);
|
||||
|
||||
if (header.innerText) {
|
||||
titles.push(header.innerText);
|
||||
} else {
|
||||
titles.push(header.textContent);
|
||||
}
|
||||
}
|
||||
|
||||
return titles;
|
||||
}
|
||||
|
||||
function findChildElements(container, name, targetClass) {
|
||||
var elements = [];
|
||||
var children = container.childNodes;
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var child = children.item(i);
|
||||
|
||||
if (child.nodeType === 1 && child.nodeName === name) {
|
||||
if (targetClass && child.className.indexOf(targetClass) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
elements.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
// Entry point.
|
||||
|
||||
window.onload = function() {
|
||||
initTabs();
|
||||
initControls();
|
||||
};
|
||||
} (window, window.document));
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
|
||||
<title>Test results - Package com.unicorn.lifesub.member.test.unit.config.jwt</title>
|
||||
<link href="../css/base-style.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="../js/report.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<h1>Package com.unicorn.lifesub.member.test.unit.config.jwt</h1>
|
||||
<div class="breadcrumbs">
|
||||
<a href="../index.html">all</a> > com.unicorn.lifesub.member.test.unit.config.jwt</div>
|
||||
<div id="summary">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="summaryGroup">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="infoBox" id="tests">
|
||||
<div class="counter">3</div>
|
||||
<p>tests</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="failures">
|
||||
<div class="counter">0</div>
|
||||
<p>failures</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="ignored">
|
||||
<div class="counter">0</div>
|
||||
<p>ignored</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox" id="duration">
|
||||
<div class="counter">1.064s</div>
|
||||
<p>duration</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="infoBox success" id="successRate">
|
||||
<div class="percent">100%</div>
|
||||
<p>successful</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="tabs">
|
||||
<ul class="tabLinks">
|
||||
<li>
|
||||
<a href="#tab0">Classes</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="tab0" class="tab">
|
||||
<h2>Classes</h2>
|
||||
<table>
|
||||
<thread>
|
||||
<tr>
|
||||
<th>Class</th>
|
||||
<th>Tests</th>
|
||||
<th>Failures</th>
|
||||
<th>Ignored</th>
|
||||
<th>Duration</th>
|
||||
<th>Success rate</th>
|
||||
</tr>
|
||||
</thread>
|
||||
<tr>
|
||||
<td class="success">
|
||||
<a href="../classes/com.unicorn.lifesub.member.test.unit.config.jwt.CustomUserDetailsServiceTest.html">CustomUserDetailsServiceTest</a>
|
||||
</td>
|
||||
<td>3</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>1.064s</td>
|
||||
<td class="success">100%</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>
|
||||
<div>
|
||||
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
|
||||
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
|
||||
</label>
|
||||
</div>Generated by
|
||||
<a href="http://www.gradle.org">Gradle 8.4</a> at 2025. 2. 14. 오후 4:50:22</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuite name="com.unicorn.lifesub.member.test.unit.config.jwt.CustomUserDetailsServiceTest" tests="3" skipped="0" failures="0" errors="0" timestamp="2025-02-14T07:50:21" hostname="ihaegyeong-ui-MacBookAir.local" time="1.069">
|
||||
<properties/>
|
||||
<testcase name="givenNonExistentUserId_whenLoadUser_thenThrowException" classname="com.unicorn.lifesub.member.test.unit.config.jwt.CustomUserDetailsServiceTest" time="0.864"/>
|
||||
<testcase name="givenUserWithRoles_whenLoadUser_thenMapAuthoritiesCorrectly" classname="com.unicorn.lifesub.member.test.unit.config.jwt.CustomUserDetailsServiceTest" time="0.192"/>
|
||||
<testcase name="givenExistingUserId_whenLoadUser_thenReturnUserDetails" classname="com.unicorn.lifesub.member.test.unit.config.jwt.CustomUserDetailsServiceTest" time="0.008"/>
|
||||
<system-out><![CDATA[]]></system-out>
|
||||
<system-err><![CDATA[]]></system-err>
|
||||
</testsuite>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,12 +2,14 @@ package com.unicorn.lifesub.member.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class LoginRequest {
|
||||
@NotBlank(message = "사용자 ID는 필수입니다.")
|
||||
private String userId;
|
||||
|
||||
|
||||
@NotBlank(message = "비밀번호는 필수입니다.")
|
||||
private String password;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package com.unicorn.lifesub.member.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class LogoutRequest {
|
||||
@NotBlank(message = "사용자 ID는 필수입니다.")
|
||||
private String userId;
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package com.unicorn.lifesub.member.test.unit.config.jwt;
|
||||
|
||||
import com.unicorn.lifesub.member.config.jwt.CustomUserDetailsService;
|
||||
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
|
||||
import com.unicorn.lifesub.member.repository.jpa.MemberRepository;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* 사용자 상세 정보 서비스 테스트 클래스
|
||||
* Spring Security의 UserDetailsService 구현체 검증
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CustomUserDetailsServiceTest {
|
||||
|
||||
@InjectMocks
|
||||
private CustomUserDetailsService userDetailsService;
|
||||
|
||||
@Mock
|
||||
private MemberRepository memberRepository;
|
||||
|
||||
// 테스트용 상수 정의
|
||||
private static final String TEST_USER_ID = "testUser";
|
||||
private static final String TEST_PASSWORD = "testPassword";
|
||||
private static final String TEST_USER_NAME = "Test User";
|
||||
|
||||
/**
|
||||
* 사용자 조회 성공 케이스 테스트
|
||||
* 존재하는 사용자 ID로 조회 시 UserDetails 객체가 정상적으로 반환되는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenExistingUserId_whenLoadUser_thenReturnUserDetails")
|
||||
void givenExistingUserId_whenLoadUser_thenReturnUserDetails() {
|
||||
// Given
|
||||
MemberEntity memberEntity = createTestMemberEntity();
|
||||
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
|
||||
|
||||
// When
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(TEST_USER_ID);
|
||||
|
||||
// Then
|
||||
assertThat(userDetails).isNotNull();
|
||||
assertThat(userDetails.getUsername()).isEqualTo(TEST_USER_ID);
|
||||
assertThat(userDetails.getPassword()).isEqualTo(TEST_PASSWORD);
|
||||
assertThat(userDetails.getAuthorities()).hasSize(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 조회 실패 케이스 테스트
|
||||
* 존재하지 않는 사용자 ID로 조회 시 적절한 예외가 발생하는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenNonExistentUserId_whenLoadUser_thenThrowException")
|
||||
void givenNonExistentUserId_whenLoadUser_thenThrowException() {
|
||||
// Given
|
||||
String nonExistentUserId = "nonexistent";
|
||||
given(memberRepository.findByUserId(nonExistentUserId)).willReturn(Optional.empty());
|
||||
|
||||
// When & Then
|
||||
assertThrows(UsernameNotFoundException.class, () ->
|
||||
userDetailsService.loadUserByUsername(nonExistentUserId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 권한 매핑 테스트
|
||||
* 사용자의 역할이 Spring Security 권한으로 올바르게 매핑되는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenUserWithRoles_whenLoadUser_thenMapAuthoritiesCorrectly")
|
||||
void givenUserWithRoles_whenLoadUser_thenMapAuthoritiesCorrectly() {
|
||||
// Given
|
||||
MemberEntity memberEntity = createTestMemberEntityWithMultipleRoles();
|
||||
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
|
||||
|
||||
// When
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(TEST_USER_ID);
|
||||
|
||||
// Then
|
||||
assertThat(userDetails.getAuthorities()).hasSize(2);
|
||||
assertThat(userDetails.getAuthorities())
|
||||
.extracting("authority")
|
||||
.containsExactlyInAnyOrder("USER", "ADMIN");
|
||||
}
|
||||
|
||||
// 테스트 헬퍼 메서드
|
||||
private MemberEntity createTestMemberEntity() {
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
return MemberEntity.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USER_NAME)
|
||||
.password(TEST_PASSWORD)
|
||||
.roles(roles)
|
||||
.build();
|
||||
}
|
||||
|
||||
private MemberEntity createTestMemberEntityWithMultipleRoles() {
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
roles.add("ADMIN");
|
||||
return MemberEntity.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USER_NAME)
|
||||
.password(TEST_PASSWORD)
|
||||
.roles(roles)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package com.unicorn.lifesub.member.test.unit.config.jwt;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.unicorn.lifesub.common.dto.JwtTokenDTO;
|
||||
import com.unicorn.lifesub.common.exception.InfraException;
|
||||
import com.unicorn.lifesub.member.config.jwt.JwtTokenProvider;
|
||||
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* JWT 토큰 제공자 테스트 클래스
|
||||
* 토큰 생성, 검증, 파싱 등의 기능을 검증
|
||||
*/
|
||||
class JwtTokenProviderTest {
|
||||
|
||||
private JwtTokenProvider jwtTokenProvider;
|
||||
private static final String SECRET_KEY = "test-secret-key";
|
||||
private static final long ACCESS_TOKEN_VALIDITY = 3600000;
|
||||
private static final long REFRESH_TOKEN_VALIDITY = 86400000;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
jwtTokenProvider = new JwtTokenProvider(SECRET_KEY, ACCESS_TOKEN_VALIDITY, REFRESH_TOKEN_VALIDITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰 생성 테스트
|
||||
* 유효한 사용자 정보로 JWT 토큰이 정상적으로 생성되는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenValidMember_whenCreateToken_thenSuccess")
|
||||
void givenValidMember_whenCreateToken_thenSuccess() {
|
||||
// Given
|
||||
MemberEntity member = createTestMemberEntity();
|
||||
Set<SimpleGrantedAuthority> authorities = Collections.singleton(
|
||||
new SimpleGrantedAuthority("ROLE_USER"));
|
||||
|
||||
// When
|
||||
JwtTokenDTO tokens = jwtTokenProvider.createToken(member, authorities);
|
||||
|
||||
// Then
|
||||
assertThat(tokens).isNotNull();
|
||||
assertThat(tokens.getAccessToken()).isNotNull();
|
||||
assertThat(tokens.getRefreshToken()).isNotNull();
|
||||
assertThat(jwtTokenProvider.validateToken(tokens.getAccessToken())).isEqualTo(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰 검증 테스트
|
||||
* 유효한 토큰과 유효하지 않은 토큰에 대한 검증이 정상적으로 동작하는지 확인
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenToken_whenValidate_thenSuccess")
|
||||
void givenToken_whenValidate_thenSuccess() {
|
||||
// Given
|
||||
String token = createValidToken();
|
||||
|
||||
// When & Then
|
||||
assertThat(jwtTokenProvider.validateToken(token)).isEqualTo(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증 정보 추출 테스트
|
||||
* JWT 토큰에서 인증 정보가 정상적으로 추출되는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenValidToken_whenGetAuthentication_thenSuccess")
|
||||
void givenValidToken_whenGetAuthentication_thenSuccess() {
|
||||
// Given
|
||||
String token = createValidToken();
|
||||
|
||||
// When
|
||||
Authentication authentication = jwtTokenProvider.getAuthentication(token);
|
||||
|
||||
// Then
|
||||
assertThat(authentication).isNotNull();
|
||||
assertThat(authentication.isAuthenticated()).isTrue();
|
||||
assertThat(authentication.getAuthorities()).hasSize(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰 추출 테스트
|
||||
* HTTP 요청 헤더에서 토큰이 정상적으로 추출되는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenRequest_whenResolveToken_thenSuccess")
|
||||
void givenRequest_whenResolveToken_thenSuccess() {
|
||||
// Given
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
String token = "test-token";
|
||||
when(request.getHeader("Authorization")).thenReturn("Bearer " + token);
|
||||
|
||||
// When
|
||||
String resolvedToken = jwtTokenProvider.resolveToken(request);
|
||||
|
||||
// Then
|
||||
assertThat(resolvedToken).isEqualTo(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 유효하지 않은 토큰 검증 테스트
|
||||
* 잘못된 형식의 토큰에 대해 적절한 예외가 발생하는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenInvalidToken_whenValidate_thenThrowException")
|
||||
void givenInvalidToken_whenValidate_thenThrowException() {
|
||||
// Given
|
||||
String invalidToken = "invalid-token";
|
||||
|
||||
// When & Then
|
||||
assertThrows(InfraException.class, () -> jwtTokenProvider.validateToken(invalidToken));
|
||||
}
|
||||
|
||||
// 테스트 헬퍼 메서드
|
||||
private MemberEntity createTestMemberEntity() {
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
return MemberEntity.builder()
|
||||
.userId("testUser")
|
||||
.userName("Test User")
|
||||
.password("password")
|
||||
.roles(roles)
|
||||
.build();
|
||||
}
|
||||
|
||||
private String createValidToken() {
|
||||
Algorithm algorithm = Algorithm.HMAC512(SECRET_KEY);
|
||||
return JWT.create()
|
||||
.withSubject("testUser")
|
||||
.withClaim("auth", Collections.singletonList("ROLE_USER"))
|
||||
.sign(algorithm);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.unicorn.lifesub.member.test.unit.domain;
|
||||
|
||||
import com.unicorn.lifesub.member.domain.Member;
|
||||
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Member 도메인 객체 테스트 클래스
|
||||
* 도메인 객체의 생성 및 엔티티 변환 로직을 검증
|
||||
*/
|
||||
class MemberTest {
|
||||
|
||||
// 테스트용 상수 정의
|
||||
private static final String TEST_USER_ID = "testUser";
|
||||
private static final String TEST_USER_NAME = "Test User";
|
||||
private static final String TEST_PASSWORD = "testPassword";
|
||||
|
||||
/**
|
||||
* Member 객체 생성 테스트
|
||||
* Builder 패턴을 사용한 Member 객체 생성이 정상적으로 동작하는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenMemberInfo_whenBuildMember_thenSuccess")
|
||||
void givenMemberInfo_whenBuildMember_thenSuccess() {
|
||||
// Given
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
|
||||
// When
|
||||
Member member = Member.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USER_NAME)
|
||||
.password(TEST_PASSWORD)
|
||||
.roles(roles)
|
||||
.build();
|
||||
|
||||
// Then
|
||||
assertThat(member).isNotNull();
|
||||
assertThat(member.getUserId()).isEqualTo(TEST_USER_ID);
|
||||
assertThat(member.getUserName()).isEqualTo(TEST_USER_NAME);
|
||||
assertThat(member.getPassword()).isEqualTo(TEST_PASSWORD);
|
||||
assertThat(member.getRoles()).containsExactly("USER");
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity에서 Domain 객체로의 변환 테스트
|
||||
* MemberEntity.toDomain() 메서드가 정상적으로 동작하는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenMemberEntity_whenConvertToDomain_thenSuccess")
|
||||
void givenMemberEntity_whenConvertToDomain_thenSuccess() {
|
||||
// Given
|
||||
MemberEntity entity = createTestMemberEntity();
|
||||
|
||||
// When
|
||||
Member member = entity.toDomain();
|
||||
|
||||
// Then
|
||||
assertThat(member).isNotNull();
|
||||
assertThat(member.getUserId()).isEqualTo(TEST_USER_ID);
|
||||
assertThat(member.getUserName()).isEqualTo(TEST_USER_NAME);
|
||||
assertThat(member.getPassword()).isEqualTo(TEST_PASSWORD);
|
||||
assertThat(member.getRoles()).containsExactly("USER");
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain 객체에서 Entity로의 변환 테스트
|
||||
* MemberEntity.fromDomain() 메서드가 정상적으로 동작하는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenMemberDomain_whenConvertToEntity_thenSuccess")
|
||||
void givenMemberDomain_whenConvertToEntity_thenSuccess() {
|
||||
// Given
|
||||
Member member = createTestMember();
|
||||
|
||||
// When
|
||||
MemberEntity entity = MemberEntity.fromDomain(member);
|
||||
|
||||
// Then
|
||||
assertThat(entity).isNotNull();
|
||||
assertThat(entity.getUserId()).isEqualTo(TEST_USER_ID);
|
||||
assertThat(entity.getUserName()).isEqualTo(TEST_USER_NAME);
|
||||
assertThat(entity.getPassword()).isEqualTo(TEST_PASSWORD);
|
||||
assertThat(entity.getRoles()).containsExactly("USER");
|
||||
}
|
||||
|
||||
/**
|
||||
* 다중 역할을 가진 Member 객체 생성 테스트
|
||||
* 여러 역할을 가진 Member 객체가 정상적으로 생성되는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenMultipleRoles_whenBuildMember_thenSuccess")
|
||||
void givenMultipleRoles_whenBuildMember_thenSuccess() {
|
||||
// Given
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
roles.add("ADMIN");
|
||||
|
||||
// When
|
||||
Member member = Member.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USER_NAME)
|
||||
.password(TEST_PASSWORD)
|
||||
.roles(roles)
|
||||
.build();
|
||||
|
||||
// Then
|
||||
assertThat(member).isNotNull();
|
||||
assertThat(member.getRoles()).hasSize(2);
|
||||
assertThat(member.getRoles()).containsExactlyInAnyOrder("USER", "ADMIN");
|
||||
}
|
||||
|
||||
// 테스트 헬퍼 메서드
|
||||
private MemberEntity createTestMemberEntity() {
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
return MemberEntity.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USER_NAME)
|
||||
.password(TEST_PASSWORD)
|
||||
.roles(roles)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Member createTestMember() {
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
return Member.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USER_NAME)
|
||||
.password(TEST_PASSWORD)
|
||||
.roles(roles)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package com.unicorn.lifesub.member.test.unit.service;
|
||||
|
||||
import com.unicorn.lifesub.common.dto.JwtTokenDTO;
|
||||
import com.unicorn.lifesub.common.exception.BusinessException;
|
||||
import com.unicorn.lifesub.common.exception.ErrorCode;
|
||||
import com.unicorn.lifesub.common.exception.InfraException;
|
||||
import com.unicorn.lifesub.member.config.jwt.JwtTokenProvider;
|
||||
import com.unicorn.lifesub.member.dto.LoginRequest;
|
||||
import com.unicorn.lifesub.member.dto.LogoutRequest;
|
||||
import com.unicorn.lifesub.member.repository.entity.MemberEntity;
|
||||
import com.unicorn.lifesub.member.repository.jpa.MemberRepository;
|
||||
import com.unicorn.lifesub.member.service.MemberServiceImpl;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* 멤버 서비스 테스트 클래스
|
||||
* 주요 비즈니스 로직인 로그인/로그아웃 기능을 검증
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MemberServiceImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private MemberServiceImpl memberService;
|
||||
|
||||
@Mock
|
||||
private MemberRepository memberRepository;
|
||||
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Mock
|
||||
private JwtTokenProvider jwtTokenProvider;
|
||||
|
||||
// 테스트용 상수 정의
|
||||
private static final String TEST_USER_ID = "testUser";
|
||||
private static final String TEST_PASSWORD = "testPassword";
|
||||
private static final String TEST_USER_NAME = "Test User";
|
||||
|
||||
/**
|
||||
* 로그인 성공 케이스 테스트
|
||||
* 올바른 사용자 ID와 비밀번호로 로그인 시 JWT 토큰이 정상적으로 발급되는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenValidCredentials_whenLogin_thenSuccess")
|
||||
void givenValidCredentials_whenLogin_thenSuccess() {
|
||||
// Given
|
||||
LoginRequest request = new LoginRequest();
|
||||
request.setUserId(TEST_USER_ID);
|
||||
request.setPassword(TEST_PASSWORD);
|
||||
|
||||
MemberEntity memberEntity = createTestMemberEntity();
|
||||
JwtTokenDTO expectedToken = createTestJwtTokenDTO();
|
||||
|
||||
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
|
||||
given(passwordEncoder.matches(TEST_PASSWORD, memberEntity.getPassword())).willReturn(true);
|
||||
given(jwtTokenProvider.createToken(any(), any())).willReturn(expectedToken);
|
||||
|
||||
// When
|
||||
JwtTokenDTO result = memberService.login(request);
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getAccessToken()).isEqualTo(expectedToken.getAccessToken());
|
||||
assertThat(result.getRefreshToken()).isEqualTo(expectedToken.getRefreshToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 실패 케이스 테스트 - 사용자가 존재하지 않는 경우
|
||||
* 존재하지 않는 사용자 ID로 로그인 시도 시 적절한 예외가 발생하는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenNonExistentUser_whenLogin_thenThrowException")
|
||||
void givenNonExistentUser_whenLogin_thenThrowException() {
|
||||
// Given
|
||||
LoginRequest request = new LoginRequest();
|
||||
request.setUserId("nonexistent");
|
||||
request.setPassword(TEST_PASSWORD);
|
||||
|
||||
when(memberRepository.findByUserId("nonexistent")).thenReturn(Optional.empty());
|
||||
|
||||
// When & Then
|
||||
InfraException exception = assertThrows(InfraException.class,
|
||||
() -> memberService.login(request));
|
||||
assertThat(exception.getErrorCode()).isEqualTo(ErrorCode.MEMBER_NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 실패 케이스 테스트 - 잘못된 비밀번호
|
||||
* 올바른 사용자 ID와 잘못된 비밀번호로 로그인 시도 시 적절한 예외가 발생하는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenInvalidPassword_whenLogin_thenThrowException")
|
||||
void givenInvalidPassword_whenLogin_thenThrowException() {
|
||||
// Given
|
||||
LoginRequest request = new LoginRequest();
|
||||
request.setUserId(TEST_USER_ID);
|
||||
request.setPassword("wrongPassword");
|
||||
|
||||
MemberEntity memberEntity = createTestMemberEntity();
|
||||
|
||||
given(memberRepository.findByUserId(TEST_USER_ID)).willReturn(Optional.of(memberEntity));
|
||||
given(passwordEncoder.matches("wrongPassword", memberEntity.getPassword())).willReturn(false);
|
||||
|
||||
// When & Then
|
||||
BusinessException exception = assertThrows(BusinessException.class,
|
||||
() -> memberService.login(request));
|
||||
assertThat(exception.getErrorCode()).isEqualTo(ErrorCode.INVALID_CREDENTIALS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그아웃 테스트
|
||||
* 로그아웃 요청 시 정상적으로 처리되는지 검증
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("givenLogoutRequest_whenLogout_thenSuccess")
|
||||
void givenLogoutRequest_whenLogout_thenSuccess() {
|
||||
// Given
|
||||
LogoutRequest request = new LogoutRequest();
|
||||
request.setUserId(TEST_USER_ID);
|
||||
|
||||
// When
|
||||
var response = memberService.logout(request);
|
||||
|
||||
// Then
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.getMessage()).contains("로그아웃이 완료되었습니다");
|
||||
}
|
||||
|
||||
// 테스트 헬퍼 메서드
|
||||
private MemberEntity createTestMemberEntity() {
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.add("USER");
|
||||
return MemberEntity.builder()
|
||||
.userId(TEST_USER_ID)
|
||||
.userName(TEST_USER_NAME)
|
||||
.password(TEST_PASSWORD)
|
||||
.roles(roles)
|
||||
.build();
|
||||
}
|
||||
|
||||
private JwtTokenDTO createTestJwtTokenDTO() {
|
||||
return JwtTokenDTO.builder()
|
||||
.accessToken("test-access-token")
|
||||
.refreshToken("test-refresh-token")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user