๋ณธ๋ฌธ

[jUnit][mock] ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

 

๐Ÿ’ก JUnit

1. JUnit์„ ์ด์šฉํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

JUnit์€ ์ž๋ฐ”์šฉ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์„ ์œ„ํ•œ ์‚ฐ์—… ํ‘œ์ค€ ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค.

 

2. ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ

ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑ(Maven or Gradle or whatever)ํ•˜๋ฉด ๊ธฐ๋ณธ์˜ต์…˜์œผ๋กœ jUnit์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

eclipse version: 2019-09 R (4.13.0)

 

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
	}

}

 

 

 

 

 

 

์ฐธ๊ณ  https://using.tistory.com/54

๊ณต์œ 

๋Œ“๊ธ€

Cloud & AI Engineering | ์ž„์Šนํ•œ

design by tokiidesu. powerd by AXZ.