본문

[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

반응형

공유

댓글