๋ณธ๋ฌธ
[jUnit][mock] ๋จ์ ํ ์คํธ
๐ก JUnit
1. JUnit์ ์ด์ฉํ ๋จ์ ํ ์คํธ
JUnit์ ์๋ฐ์ฉ ๋จ์ ํ ์คํธ ์์ฑ์ ์ํ ์ฐ์ ํ์ค ํ๋ ์์ํฌ์ด๋ค.
2. ํ๋ก์ ํธ ๊ตฌ์ฑ
ํ๋ก์ ํธ๋ฅผ ์์ฑ(Maven or Gradle or whatever)ํ๋ฉด ๊ธฐ๋ณธ์ต์ ์ผ๋ก jUnit์ด ํฌํจ๋์ด ์๋ค.

3. JUnit ํ ์คํธ
JUnit ํ ์คํธ๋ฅผ ์ํด ๊ณ์ฐ๊ธฐ ํด๋์ค๋ฅผ ์์ฑํ๋ค.

src/main/java
public class Calcurator {
public double sum(double a, double b) {
return a + b;
}
}
src/test/java
public class CalcuratorTest {
@Test
public void testSum() {
Calcurator c = new Calcurator();
double result = c.sum(10, 50);
assertEquals(60, result, 0);
}
}
๊ฒฐ๊ณผ ์์(Success)

๐ก JUnit assert ์ฃผ์ ๋ฉ์๋ ๋ฐ ์ฌ์ฉ์์
| assert ๋ฉ์๋ | ์ค๋ช |
| assertArrayEquals(a, b) | ๋ฐฐ์ด A์ B๊ฐ ์ผ์นํจ์ ํ์ธํ๋ค. |
| assertEquals(a, b) | ๊ฐ์ฒด A์ B๊ฐ ์ผ์นํจ์ ํ์ธํ๋ค. |
| assertTrue(a) | ์กฐ๊ฑด A๊ฐ ์ฐธ์ธ๊ฐ๋ฅผ ํ์ธํ๋ค. |
| assertNotNull(a) | ๊ฐ์ฒด A๊ฐ null์ด ์๋์ ํ์ธํ๋ค. |
String names[] = {"y2kpooh","hwang"};
String names2[] = {"y2kpooh","hwang"};
assertArrayEquals(names2, names);
List someList = exampleClass.getSomeList();
assertNotNull("์กฐํ๊ฒฐ๊ณผ null", someList);
assertTrue(someList.size() > 0);
assertEquals(3, someList.size());
๐ก JUnit Annotation ์ฌ์ฉ ์์
์คํ๋ง ํ๋ ์์ํฌ ๊ธฐ๋ฐ์ JUnit ํ ์คํธ๋ฅผ ์ํ ์ธํ
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:WebContent/WEB-INF/classes/applicationContext*.xml"})
Spring ๊ธฐ๋ฐ์ ํ ์คํธ ์ฝ๋ ์์ฑ์ ์ํด ํ ์คํธ ํด๋์ค ์๋จ์ @RunWith(SpringJUnit4ClassRunner.class) ๊ตฌ๋ฌธ์ ์ถ๊ฐํ๋ค.
Spring ํ๋ ์์ํฌ context ํ์ผ์ ํ
์คํธ ์ํ์์๋ ๋์ผํ๊ฒ ๋ก๋ฉํ๊ธฐ ์ํด @ContextConfiguration(locations=...xml"}) ๊ณผ ๊ฐ์ ํํ๋ก ํ๋ก์ ํธ์ ์คํ๋ง ์ค์ ํ์ผ์ ์ค์ ํด ์ค๋ค.
a) ๋ฉ์๋ ์ํ์๊ฐ ์ ํํ๊ธฐ
๋จ์๋ ๋ฐ๋ฆฌ์ด์ด๋ฉฐ ์ด ๋ฉ์๋๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋๋ฐ 5,000๋ฐ๋ฆฌ์ด๊ฐ ๋๊ธด๋ค๋ฉด ํ ์คํธ๋ ์คํจํ๋ค.
@Test(timeout=5000)
b) Exception ํ ์คํธ
ํด๋น ํด๋์ค๋ RuntimeException์ด ๋ฐ์ํด์ผ ํ๋ค. ๋ง์ฝ ํ ์คํธ์์ RuntimeException์ด ๋ฐ์ํ์ง ์์ ๊ฒฝ์ฐ ์คํจํ๋ค.
@Test(expected=RuntimeException.class)
c) ํ ์คํธ ๊ฑด๋๋ฐ๊ธฐ
@Ignore ์ด๋ ธํ ์ด์ ์ ์ถ๊ฐํ๋ฉด ํด๋น ๋ฉ์๋๋ ํ ์คํธ๋ฅผ ๊ฑด๋๋ฐ๊ฒ ๋๋ฉฐ JUnit4๋ ์ฑ๊ณต ๋ฐ ์คํจ ๊ฐ์์ ํจ๊ป ๊ฑด๋๋ด ํ ์คํธ ์๋ ํฌํ๋ ๊ฒฐ๊ณผ ํต๊ณ๋ฅผ ์ ๊ณตํ๋ค.
@Test(timeout=5000)
@Ignore(value=”์ฌ๊ธฐ๋ ํ
์คํธ ์ํ ๊ฑฐ์ผ”)
d) ์ด๊ธฐํ ๋ฐ ์ข ๋ฃ
@Before ์ด๋ ธํ ์ด์ ์ด ์ ์ธ๋ ๋ฉ์๋๋ ํด๋น ํ ์คํธ ํด๋์ค์ ์ธ์คํด์ค, ๊ฐ์ฒด๋ฅผ ์ด๊ธฐํ ํ๋ ์์ ์ ํ๋ค. @After ์ด๋ ธํ ์ด์ ์ด ์ ์ธ๋ ๋ฉ์๋๋ ํด๋น ํ ์คํธ ์คํ ํ ์คํ๋๋ค. @Before, @After ์ด๋ ธํ ์ด์ ์ด์ธ์ @BeforeClass, @AfterClass๋ ์๋๋ฐ, ์ด ์ด๋ ธํ ์ด์ ๋ค์ static ๋ฉ์๋์ ๋์ผํ ํํ๋ก ํ ์คํธ ํด๋์ค ์คํ ์ ํ๋ฒ๋ง ์คํ๋๋ค.
@Before
[...]
@After
[...]
๐ก JUnit with Mock - ๋ชฉ(Mock) ๊ฐ์ฒด๋ฅผ ํ์ฉํ ํ ์คํธ
์ํ ๊ณ์ข์์ ๋ค๋ฅธ ๊ณ์ข๋ก ์ก๊ธํ๋ ๋จ์ํ ํ ์คํธ ์ผ์ด์ค์ด๋ค. ์๋์ ๊ณ์ข ์ก๊ธ ํ๋ก์ธ์ค๋ฅผ ๊ธฐ๋ฅ ํ ์คํธ ํ๊ธฐ ์ํด์๋ DB๋ฅผ ์ค์นํ ๋ค ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์ฑ์๋ฃ๋ ์์ ์ ํด์ผํ์ง๋ง, Mock์ ์ด์ฉํ๋ฉด DB๋ฅผ ์ฐ๋ํด์ผํ๋ ๋ฒ๊ฑฐ๋ก์ ์์ด ์ฝ๋๋ฅผ ํ ์คํธํ ์ ์๋ค. ๋จ ์ธํฐํ์ด์ค๊ฐ ์ ์๋์ด ์์ด์ผ ํ๋ค.
โป Mock Object๋, ํ ์คํธํ๊ณ ์ ํ๋ ์ฝ๋์์ ์ค์ ๋ก ๊ตฌํํ๊ธฐ ์ด๋ ค์ด ๊ฐ์ฒด๋ค์ ๋์ ํ์ฌ ๋์ํ๊ธฐ ์ํด ๋ง๋ค์ด์ง ๊ฐ์ฒด์ด๋ค. ํ ์คํธ ์ Mock Object์ ๋ฏธ๋ฆฌ ์ ์๋ ๊ฒฐ๊ณผ๋ฅผ ํตํด์ ํ ์คํธ๋ฅผ ์์ํ๊ฒ ์งํํ ์ ์๋ค.

src/main/java
public class Account {
private String accountId;
private long balance;
public Account(String accountId, long initialBalance) {
this.accountId = accountId;
this.balance = initialBalance;
}
// ์ถ๊ธ
public void debit(long amount) {
this.balance -= amount;
}
// ์
๊ธ
public void credit(long amount) {
this.balance += amount;
}
public String getAccountId() {
return this.accountId;
}
public long getBalance() {
return this.balance;
}
}
public interface AccountManager {
// id๋ก ๊ณ์ข ๊ณ์ ์ฐพ๊ธฐ
Account findAccountForUser(String userId);
// ๊ณ์ข ๊ณ์ ์
๋ฐ์ดํธ
void updateAccount(Account account);
}
// ๋ ๊ณ์ ์ฌ์ด์ ์ก๊ธ ๊ธฐ๋ฅ์ ์ ๊ณต
public class AccountService {
private AccountManager accountManager;
public void setAccountManager(AccountManager manager) {
this.accountManager = manager;
}
// ์ก๊ธ
public void transfer(String senderId, String receiverId, long amount) {
Account sender = this.accountManager.findAccountForUser(senderId);
Account receiver = this.accountManager.findAccountForUser(receiverId);
sender.debit(amount);
receiver.credit(amount);
this.accountManager.updateAccount(sender);
this.accountManager.updateAccount(receiver);
}
}
// AccountService.transfer ๋ฉ์๋ ๋จ์ ํ
์คํธ๋ฅผ ์ํ Mock ๊ฐ์ฒด ๊ตฌํ
public class MockAccountManager implements AccountManager {
private Map<String, Account> accounts = new HashMap<String, Account>();
public void addAccont(String userId, Account account) {
this.accounts.put(userId, account);
}
public Account findAccountForUser(String userId) {
return this.accounts.get(userId);
}
public void updateAccount(Account account) {
// TODO Auto-generated method stub
}
}
src/test/java
public class TestAccountService {
@Test
public void testTransferOk() {
// test๋ฅผ ์ํ ๊ฐ์ฒด ์์ฑ/์ค๋น
String senderId = "CheolSu";
String receiverId = "YeongMi";
Account senderAccount = new Account(senderId, 200);
Account receiverAccount = new Account(receiverId, 100);
MockAccountManager mockAccountManager = new MockAccountManager();
mockAccountManager.addAccont(senderAccount.getAccountId(), senderAccount);
mockAccountManager.addAccont(receiverAccount.getAccountId(), receiverAccount);
AccountService accountService = new AccountService();
accountService.setAccountManager(mockAccountManager);
// ํ
์คํธ
accountService.transfer(senderId, receiverId, 50);
// ๊ฒฐ๊ณผ ๊ฒ์ฆ
assertEquals(150, senderAccount.getBalance()); // 200 - 50 = 150
assertEquals(150, receiverAccount.getBalance()); // 100 + 50 = 150
}
}
๋๊ธ