โจ๐๐ซํ ์คํธ๐ซ๐โจ (ํ ๋น์ ์คํ๋ง)
ํด๋น ํฌ์คํ ์ ํ ๋น์ ์คํ๋ง 3.1์ ์ฝ๊ณ ์ฑ ๋ด์ฉ๊ณผ ์ค์ต ์ฝ๋ ์ ๋ฆฌ ๋ฐ ์คํฐ๋์์ ๋์จ ์๊ฒฌ์ ์ ๋ฆฌํ ํฌ์คํ ์ด๋ค.
2์ฅ ํ ์คํธ
์คํ๋ง์ ๊ตญ๋นํ์์์ ์ฒ์ ๋ฐฐ์ด ๋๋ ํ
์คํธ
๊ฐ ์กด์ฌํ๋ ์ค๋ ๋ชฐ๋๋ค.
์์ํ ์ฝ๋ ํ๋ ๊ณ ์น๋ ๋ฐ๋ ๋์๋์ด ์ผ์ด๋ฌ๋ค.
ํ์๊ฐ์
๊ธฐ๋ฅ์ ๋ง๋๋๋ฐ ๋น๋ฐ๋ฒํธ ์ ํ์ด ์ ์๋๋ ๊ฒ ๊ฐ๋ค๋ฉด
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์ข ๋ฃํ๋ค
- ์ฝ๋๋ฅผ ์์ ํ๊ณ break point๋ฅผ ๊ฑธ๊ฑฐ๋ ์ถ๋ ฅ๋ฌธ์ ์จ๋๋ค
- ๋ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํจ๋ค
- ํฌ๋กฌ ์ํฌ๋ฆฟ + ๊ฐ๋ ฅ ์๋ก๊ณ ์นจ์ผ๋ก ํ์ด์ง์ ๋ค์ด๊ฐ๋ค
- ํ์๊ฐ์ ์ ์๋ํ๊ณ ๋ค์ ํ์ธํ๋ค
์ด๋ฐ ๊ณผ์ ์ ๊ฑฐ์ณ์ผ ํ๋ค.
ํ ์คํธ๊ฐ ์ผ์์ด ๋ ์ง๊ธ์ ํ ์คํธ๊ฐ ์์ผ๋ฉด ๋ถ์ํ๋ค. (๋ ๋ฒจ4 ๋ฏธ์ ์ ํ๋ฉด์ ์ํํด์ง๊ธด ํ์ง๋งโฆ) ํ ์คํธ๋ฅผ ๋ฐฐ์ด ์ฒ์์ ์ ๊ธฐํ๊ณ , ๊ทธ ๋ค์์ ์กฐ๊ธ ๊ท์ฐฎ์๋๋ฐ, ์ง๊ธ์ ํ ์คํธ๊ฐ ์์ผ๋ฉด ์ค ์์ด ๋ฒ์ง์ ํํ๋ ๊ธฐ๋ถ์ด ๋ ๋ค. ํ ์คํธ๋ ๋์๊ฒ ์์ ๋กญ๊ณ ์ฌ๋ฐ๊ฒ ์ฝ๋๋ฅผ ๊ฐ๊ณ ๋๊ฒ ํด์ฃผ๋ ์์ ์ฅ์น์ธ ์ ์ด๋ค.
์ด๋๊ฐ UserDaoTest ๊ฐ์ ๊ธฐ
1์ฅ์์ ๋ง๋ค์๋ UserDaoTest
๋ ๋ด๊ฐ ์์ ์ ํ๋ ํด๋จผ-ํ
์คํธ๋ณด๋จ ๋ซ์ง๋ง ์ฌ์ ํ ์ด๋๊ฐํ ํ
์คํธ๋ค.
public class UserDaoTest {
public static void main(String[] args) throws SQLException {
UserDao userDao = new DaoFactory().userDao();
User user = new User("hyewoncc4", "์ตํ์", "password");
userDao.add(user);
System.out.println("๋ฑ๋ก ์ฑ๊ณต");
User foundUser = userDao.get(user.getId());
System.out.println(foundUser.getName());
System.out.println(foundUser.getPassword());
System.out.println(foundUser.getId() + " ์กฐํ ์ฑ๊ณต");
}
}
- ์๋์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด์ผ ํ๋ค
์ด ์ฝ๋๋ ์๋ํ๊ฐ ๋ ๋์๋ค.
์ฝ์ ์ฐฝ์ ์ฐํ getName(), getPassword()
๊ฐ ์ ๋ง ์ ์ฅ ๋ ๊ฐ๊ณผ ์ผ์นํ๋์ง๋ ๊ฒฐ๊ตญ ์ฌ๋์ด ๋ณด๊ณ ํ๋จํด์ผ ํ๋ค.
- ์คํ ์์ ์ด ๋ฒ๊ฑฐ๋กญ๋ค
ํ์ฌ๋ ํ
์คํธ ํด๋์ค๊ฐ ํ๋๋ฟ์ด์ง๋ง, ์ด๋ฐ ์์ผ๋ก ๋ด๋ถ์ main()
์ ํตํด ํ
์คํธํ๋ ํด๋์ค๊ฐ ๋์ด๋๋ค๋ฉด ์ผ์ผํ ์คํํ๋ ๊ฒ๋ ๋ณดํต ์ผ์ด ์๋๊ฒ ๋ ๊ฒ์ด๋ค.
์ฒซ๋ฒ์งธ ๋ฌธ์ ๋ ์ฝ๋๋ฅผ ๊ฐ์ ํด ํด๊ฒฐํ ์ ์๋ค.
public static void main(String[] args) throws SQLException {
UserDao userDao = new DaoFactory().userDao();
userDao.add(user);
User user = new User("hyewoncc4", "์ตํ์", "password");
User foundUser = userDao.get(user.getId());
if (!user.getName().equals(foundUser.getName())) {
System.out.println("ํ
์คํธ ์คํจ : name");
}
else if (!user.getPassword().equals(foundUser.getPassword())) {
System.out.println("ํ
์คํธ ์คํจ : password");
} else {
System.out.println("์กฐํ ํ
์คํธ ์ฑ๊ณต");
}
}
์ด์ ์ฝ์์ฐฝ์์ ๊ฐ์ ํ์ธํ์ง ์์๋ ๋๋ค. ํ์ง๋ง ์ฌ์ ํ ๋ฌธ์ ๊ฐ ๋จ์์๋ค.
Junit ์ ์ฉํ๊ธฐ
์ด ํ
์คํธ๋ฅผ Junit
ํ๋ ์์ํฌ๋ฅผ ์ด์ฉํด ๋ฐ๊ฟ๋ณด์.
์ฑ
์์๋ Junit4
๋ฅผ ์ฌ์ฉํ๊ณ ์์ง๋ง, Junit5
๋ก ์์ ๋ฅผ ๋ฐ๋ผํ๋ค.
testImplementation("org.junit.jupiter:junit-jupiter-api")
1์ฅ์ xml
๋ถ๋ถ์ ์ฝ๋๋ก ๋ฐ๋ผํ์ง ์์๊ณ , @Configuration
์ ํตํด ๋น์ ์์ฑํด์ ์ฑ
๊ณผ ๋ค๋ฅธ ๋ถ๋ถ์ด ์๋ค.
class UserDaoTest {
@DisplayName("์ฌ์ฉ์ ์ถ๊ฐ ๋ฐ ์กฐํ")
@Test
void addAndGet() throws SQLException {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
User user = new User("yellow-cat", "๋
ธ๋ ๊ณ ์์ด", "password");
userDao.add(user);
User foundUser = userDao.get(user.getId());
assertEquals(user.getName(), foundUser.getName());
assertEquals(user.getPassword(), foundUser.getPassword());
}
}
ํ
์คํธ๋ฅผ ๋๋ฆฌ๋ฉด ํ๋ฒ๋ง ์ ์์ ์ผ๋ก ๋์๊ฐ๋ค.
๋ค์ ์คํํ๋ฉด ์ ๋ํฌ ๊ฐ ์ค๋ณต์ผ๋ก insert
์ ์คํจํ๊ธฐ ๋๋ฌธ์ด๋ค.
ํ
์คํธ๋ฅผ ์ฑ๊ณต์ํค๋ ค๋ฉด DB์ ๋ฐ์ดํฐ๋ฅผ ๋น์์ค์ผ ํ๋ค.
์ด๋ฅผ UserDao
์ deleteAll(), getCount()
๋ฉ์๋๋ฅผ ๋ง๋ฆ์ผ๋ก์จ ๋ณด์ถฉํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ฑ
์์ ์ ํ
์คํธ ์คํ์ผ์ด ๋ง์ง ์์, ๊ฒฐ๊ตญ ์คํ๋ง ๋ถํธ ์คํํฐ ํ
์คํธ๋ก ์์กด์ฑ์ ๋ณ๊ฒฝํ๊ณ ํ์ ์คํ์ผ๋๋ก ์์ฑํ๋คโฆ
testImplementation("org.springframework.boot:spring-boot-starter-test")
class UserDaoTest {
@DisplayName("์ฌ์ฉ์ ์ถ๊ฐ ๋ฐ ์กฐํ")
@Test
void addAndGet() throws SQLException {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
userDao.deleteAll();
assertThat(userDao.getCount()).isEqualTo(0);
User user = new User("yellow-cat", "๋
ธ๋ ๊ณ ์์ด", "password");
userDao.add(user);
assertThat(userDao.getCount()).isEqualTo(1);
User foundUser = userDao.get(user.getId());
assertThat(foundUser.getName()).isEqualTo(user.getName());
assertThat(foundUser.getPassword()).isEqualTo(user.getPassword());
}
}
์ฑ
์๋ User
๋ฅผ ๋ ๋ฒ ์ถ๊ฐํ๊ณ getCount()
์ ๊ฐ ์ฆ๊ฐ๋ฅผ ํ์ธํ๊ณ , ๋ User
์ ๊ฐ์ ๊ฐ๊ฐ ์์ธ ๊ฒ์ฆํ๋ ์ฝ๋๊ฐ ์ถ๊ฐ๋์ด ์๋ค.
TDD๋ก ๊ฐ๋ฐํ๋ ์์ธ์ฒ๋ฆฌ
์์ธ์ฒ๋ฆฌ๋ฅผ TDD
๋ก ์๊ฐํ ๋ถ๋ถ์ด ์ธ์๊น์๋ค.
ํ์ฌ ์ฝ๋์์ userDao.get(์กด์ฌํ์ง ์๋ id)
๋ฅผ ํ๋ฉด EmptyResultDataAccessException
์ ๋ฐ์์ํค๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ณ ์ถ๋ค๊ณ ํ์.
๊ทธ๋ผ ์ ์์ ์ผ๋ก ๋์๋์ด์ผ ํ ํ
์คํธ๋ฅผ ๋จผ์ ์์ฑํ๋ค.
@DisplayName("์กด์ฌํ์ง ์๋ id ์กฐํ ์ ์์ธ")
@Test
void get_idDoesNotExists_throwException() throws SQLException {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
userDao.deleteAll();
assertThatThrownBy(() -> userDao.get("unknown_id"))
.isInstanceOf(EmptyResultDataAccessException.class);
}
์ด ํ ์คํธ๋ ๋ค๋ฅธ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด์ ์คํจํ๋ค.
java.lang.AssertionError:
Expecting:
<java.sql.SQLException: Illegal operation on empty result set.>
to be an instance of:
<org.springframework.dao.EmptyResultDataAccessException>
but was:
<"java.sql.SQLException: Illegal operation on empty result set.
์ด์ ํ
์คํธ๋ฅผ ํต๊ณผ์ํฌ ์ฝ๋๋ฅผ ๊ฐ๋ฐํ๋ฉด ๋๋ค.
id
๋ก User
๋ฅผ ์กฐํํ์ ๋ ๊ฒฐ๊ณผ๊ฐ ์๋ค๋ฉด ์์ธ๋ฅผ ๋ฐ์์ํค๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ์.
public User get(final String id) throws SQLException {
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(
"select id, name, password from users where id = ?"
);
statement.setString(1, id);
ResultSet resultSet = statement.executeQuery();
User user = null;
if (resultSet.next()) {
user = new User();
user.setId(resultSet.getString("id"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
}
resultSet.close();
statement.close();
connection.close();
if (user == null) {
throw new EmptyResultDataAccessException(1);
}
return user;
}
ํ ์คํธ๊ฐ ํต๊ณผํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
@Before๊ณผ Junit ์๋ช ์ฃผ๊ธฐ
ํ์ฌ ํ
์คํธ๋ userDao
๋น์ ์ปจํ
์ด๋์์ ๊ฐ์ ธ์ค๋ ๊ณผ์ ์ด ์ค๋ณต๋์ด์๋ค.
์ด ์ค๋ณต์ Junit์ @Before, @BeforeEach
๋ฅผ ์ด์ฉํด ์ ๊ฑฐํ ์ ์๋ค.
class UserDaoTest {
private UserDao userDao;
@BeforeEach
void setUp() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(DaoFactory.class);
userDao = applicationContext.getBean("userDao", UserDao.class);
}
@Test
void addAndGet() {...}
@Test
void get_idDoesNotExists_throwException() {...}
}
์๋ @Before
๋ ์ฌ์ฉํด๋ณด๋ ค๊ณ ํ๋๋ฐ, setUp()
์ด ํธ์ถ๋์ง ์๋ ๋ฌธ์ ๊ฐ ์์๋ค.
Junit4
์์๋ ๋ชจ๋ public
์ด์ด์ผ ํ๋ ๊ฒ ๊ฐ์์ ํด๋์ค์ ๋ฉ์๋ ์ ๊ทผ์ ์ด์๋ฅผ ๋ฐ๊พธ๊ธฐ ๋ฑ๋ฑ ์๋ํด๋ณด์๋๋ฐ ์ ์๋๋คโฆ
์ด์จ๋ addAndGet(), get_idDoesNotExists_throwException()
์ด ๊ฐ๊ฐ ์คํ๋ ๋ ์๋ก์ด UserDaoTest
์ธ์คํด์ค๊ฐ ์๊ธฐ๊ณ setUp()
์ด ํธ์ถ๋๋ค.
์ด๋ ํ
์คํธ ๊ฐ ๊ฒฉ๋ฆฌ๋ฅผ ์ํ Junit
๊ธฐ๋ณธ ์คํ์ด๋ค.
๋ง์ฝ ํ
์คํธ๊ฐ ํ๋์ ์ธ์คํด์ค์์ ์ด๋ค์ ธ์ผ ํ๋ค๋ฉด ์ด๋
ธํ
์ด์
์ผ๋ก ์๋ช
์ฃผ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.
@TestInstance(Lifecycle.PER_CLASS)
class UserDaoTest {
...
์ฑ
์์๋ ์์ฑ๋๋ User
ํฝ์ค์ณ๋ setUp()
์ ํตํด ์ค์ ํ๊ฒ ๋ฐ๊ฟ๋์๋๋ฐโฆ ๊นํ์ ์ฌ๋ฆฌ์ง ์์๋ค.
๋ง์ ๊ฒฝ์ฐ์ ํฝ์ค์ณ์ ์ด๋ฅผ ํ
์คํธํ๋ ์ฝ๋๋ ๊ฑฐ๋ฆฌ๊ฐ ๊ฐ๊น์ด ๊ฒ ์ข๋ค๋ ์๊ฐ ๋๋ฌธ์ด๋ค.
์๋ง @Before
๋ก ์ค๋ณต ์ฝ๋๋ฅผ ์ ๊ฑฐํ๋ ๋ฐฉ์์ ๋ณด์ฌ์ฃผ๋ ค๊ณ ์ฌ๊ธฐ์๋ ์ ์ฉํ์ ๊ฒ ๊ฐ๋ค.
ํ ์คํธ ๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ ๊ณต์
์์งํ ์ด ๋ถ๋ถ์ ๊ดํ ์ต์ํ ๋๋ก ํ๊ฒ ๋ค๊ณ ํ๋ค๊ฐโฆ ์ฑ
์ ์ค๋ช
์ ์ ์ดํดํ์ง ๋ชปํ๋ค.
@RunWith(SpringJunit4ClassRunner.class)
์ @SpringBootTest
๊ฐ ๋น์ทํ ์ญํ ์ ํด์ฃผ๋ ๊ฒ ๊ฐ๋ค๋ ๊ฒ๋ง ์ถ๋ก ํ๋ค.
// ๊ทธ๋ฆฌ๊ณ ์ด์ฏค์์ DaoFactory ๋ผ๋ ์ด๋ฆ์ด ๋ชน์ ์๋ชป๋์๋ค๋๊ฒ ๋ณด์ฌ์ AppConfig๋ก ๋ฐ๊ฟจ๋ค
@SpringBootTest
@ContextConfiguration(classes = DaoFactory.class)
class UserDaoTest {
@Autowired
private ApplicationContext applicationContext;
private UserDao userDao;
@BeforeEach
void setUp() {
userDao = applicationContext.getBean("userDao", UserDao.class);
}
...
์ฝ์๋ก ๊ฐ ํ
์คํธ ๋ฉ์๋์์ this(UserDaoTest์ ์ธ์คํด์ค)
์ applicationContext
๋ฅผ ์ฐ์ด๋ณด๋ฉด,
UserDaoTest
๋ ๋งค๋ฒ ์ ์ธ์คํด์ค๊ฐ ๋ง๋ค์ด์ง์๋ ๋ถ๊ตฌํ๊ณ applicationContext
์ ๊ฐ์ ์ธ์คํด์ค๊ฐ ์ฌํ์ฉ๋จ์ ๋ณผ ์ ์๋ค.
ApplicationContext
๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋๊ธฐ ๋๋ฌธ์ด๋ค.
๋ง์ฝ ๋์ผํ๊ฒ @ContextConfiguration(classes = DaoFactory.class)
๋ง ์ฌ์ฉํ๋ (๊ทธ๋ฌ๋๊น ์ ํ๋ฆฌ์ผ์ด์
์ปจํ
์คํธ ์ค์ ์ด ๊ฐ์) ๋ค๋ฅธ ํ
์คํธ ํด๋์ค๊ฐ ์๋ค๋ฉด,
๊ทธ ํด๋์ค์ ์ธ์คํด์ค๋ค๊ณผ๋ ๋์ผํ applicationContext
๋ฅผ ๊ณต์ ํ๋ค.
์ธ์ํ
์คํธ๋ฅผ ๋ฐฐ์ฐ๋ฉฐ ์๊ฒ๋ @DirtiesContext
๋ก ์๋ก์ด ์ ํ๋ฆฌ์ผ์ด์
์ปจํ
์คํธ๋ฅผ ์์ฑํ๋๋ก ๊ฐ์ ํ ์ ์๋ค.
์์ UserDao
๋ฅผ ์ฃผ์
๋ฐ๋๋ก ๋ณ๊ฒฝํ ์๋ ์๋ค.
@SpringBootTest
@ContextConfiguration(classes = AppConfig.class)
class UserDaoTest {
@Autowired
private UserDao userDao;
...
DataSource
๋ฅผ ์ฃผ์
๋ฐ์ ํ
์คํธ์์ ๋ค๋ฅธ DB๋ฅผ ์ฌ์ฉํ๋๋ก ํ ์๋ ์๋ค.
@SpringBootTest
@ContextConfiguration(classes = TestAppConfig.class)
class UserDaoTest {
@Autowired
private DataSource dataSource;
...
@Configuration
public class TestAppConfig {
@Bean
public DataSource dataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.set...;
return dataSource;
}
}
์ฑ ๊ณผ ๊ฐ์ ๋ฐฉ์์ ์๋์ง๋ง ์์ ์ ํ ์คํธ์์๋ง ๋น ๊ฐ์ ๋ผ์ฐ๊ธฐ๋ฅผ ๊ณ ๋ฏผํ ์ ์์ด์ ๋ฐ๊ฐ์ ๋ค.
์๋๋ฉด, ์ปจํ ์ด๋๋ฅผ ์์ ๋ฒ๋ฆฌ๊ธฐ
์์ํ๊ฒ UserDao
๋ง ํ
์คํธ ํ ๊ฒ์ด๋ผ๋ฉด ์ด๋ฐ ์์ผ๋ก DI
๋ฅผ ํ ์ ์๋ค.
class UserDaoTest {
private UserDao userDao;
@BeforeEach
void setUp() {
userDao = new UserDao();
userDao.setDataSource(dataSource());
}
private DataSource dataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class);
dataSource.setUrl("jdbc:mysql://localhost:3306/springbook?serverTimezone=Asia/Seoul");
dataSource.setUsername("spring");
dataSource.setPassword("book");
return dataSource;
}
...
์ฐํ
์ฝ ๋ ๋ฒจ1์์ ์ฝ์ ์ฒด์ค ๊ฒ์ ๋ง๋ค๊ธฐ ๋ฏธ์
์ ํ ๋,
์ฒด์คํ์ ๋ปํ๋ Board
๊ฐ์ฒด๋ฅผ ํ
์คํธ์์ DI
๋ฅผ ์ด์ฉํด ์ด๊ธฐํํด์คฌ๋ค.
public Board(final PiecesSetup piecesSetup) {
pieces = new Pieces(piecesSetup);
}
public interface PiecesSetup {
Map<Position, Piece> initialize();
}
@Test
@DisplayName("ํฐ์ ์๋๊ธฐ๋ฌผ์ด ๋ชฉ์ ์ง์ ์กด์ฌํ๋ฉด ๋๊ฐ์ ์ผ๋ก ์์ง์ผ ์ ์๋ค")
void pawnCanMoveDiagonal_targetExist() {
Piece whitePawn = new Piece(Color.WHITE, new Pawn());
Board board = new Board(() -> {
Map<Position, Piece> pieces = new HashMap<>();
pieces.put(Position.of("a2"), whitePawn);
pieces.put(Position.of("b3"), new Piece(Color.BLACK, new Pawn()));
return pieces;
});
board.move("a2", "b3");
assertThat(board.findPiece(Position.of("b3")).get()).isEqualTo(whitePawn);
}
์ด๋ ๊ฒ ํ
์คํธ ์ํฉ์ ๋ง๋ ๋ฐ์ดํฐ๋ฅผ ์ฃผ์
ํด ์์ฑํ ์ ์์๋ค.
DI
๊ฐ ์คํ๋ง์ ์ข
์์ ์ธ ๊ธฐ์ ์ด ์๋๋ผ๋ ๊ฑธ, ์์(?) ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์
ํ
์คํธ๋ฅผ ํตํด ์ฒด๋ํ ์ ์์๋ค.
์ ์ฒด ์ค์ต ์ฝ๋๋ ๊นํ topring ๋ ํฌ์์ ๋ณผ ์ ์๋ค.
ํ์ตํ ์คํธ๋ฅผ ๋ง๋ค์!
ํ ํ๋ง ๋ด์ฉ ์์ฝ์ ์์์ ๊ฑฐ์ ๋๋ฌ๊ณ , ์ฌ๊ธฐ๋ ๋ฒ์ธ ๋๋์ด๋ค.
ํ์ตํ
์คํธ๋ก ํ์ต์ ํ๋ฒ์ด๋ผ๋ ํด ๋ณธ ์ฌ๋๋ค์ ํ์ตํ
์คํธ์ โจ๋ฉ์งโจ์ ์ ๊ฒ์ด๋ค.
๋๋ ํ์์ XXX-sandbox
๋ผ๋ ์ด๋ฆ์ผ๋ก ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด ๊ณต๋ถํ ์ฝ๋๋ฅผ ์ ๋ฆฌํ๊ณ , ๋ธ๋ก๊ทธ์ ์ฌ๋ฆด ์์ ์ฝ๋๋ฅผ ๊นํ์ ์ฌ๋ฆฐ๋ค.
์์งํ ๊ณต๋ถ๊ฐ ์๋๋ ๊ฑด ๋์งธ์น๊ณ โฆ ์ ๋ง ํ๋ฅญํ ์ปค๋ํ์ดํผ๊ฐ ๋์ด์ค๋ค.
์ฝํ๋ฆฐ์ผ๋ก given/when/then ํ
์คํธ ์ด๋ป๊ฒ ์์ฑํ๋๋ผ? ํ๋ฉด ๊ตฌ๊ธ์์ ๊ฒ์ํ๊ณ ๋ธ๋ก๊ทธ์ ์ฝ๋๋ธ๋ญ ๊ธ์ด์ค๊ณ ํ ํ์ ์์ด ๊ทธ๋ฅ ํ๋ก์ ํธ ์ผ์ ๋ณด๋ฉด ๋๋ค.
internal class BehaviorTest: BehaviorSpec({
given("when์ผ๋ก ๋๋ฌผ ์๋ฆฌ๋ฃฐ ์ฐพ์ผ๋ฉด") {
val grammar = Grammar()
`when`("๊ณ ์์ด๋") {
val name = "cat"
val sound = grammar.whenAnimalSound(name)
then("์ผ์น์ด ๋์จ๋ค") {
sound shouldBe "meow"
}
}
`when`("๊ฐ๋") {
val name = "dog"
val sound = grammar.whenAnimalSound(name)
then("๋ฉ๋ฉ์ด ๋์จ๋ค") {
sound shouldBe "woff"
}
}
`when`("์ด๋ฆ ๋ชจ๋ฅผ ๋๋ฌผ์") {
val name = "x"
val sound = grammar.whenAnimalSound(name)
then("unknown์ด ๋์จ๋ค") {
sound shouldBe "unknown"
}
}
}
})
๋ง์ ์ฌ๋ฆฌ๋ ค๋ ๋ถ๋๋ฝ๊ธดํ๋ฐ ์ด์จ๋ ์ด๋ฐ์์ผ๋ก ์ ๋ฆฌํด๋๊ณ ์ ์ฉํ๊ฒ ๋ฒ ๋ผ๊ณ ์๋ค.
์ด๋ฒ ์ฅ์ ์ง๋๋ฒ ๋ณด๋ค ๊ฐ๋ณ๊ฒ ์ฝ์๋ค. ํ ์คํธ๋ฅผ ๋ชจ๋ฅด๋ ๋ ์ฝ์๋ค๋ฉด ์ด๋ ์๊น? ๊ฐ๋๋ฐ์์ ํ ์คํธ ์ ๋ด์๊ฐ ๋์์๊น, ์๋๋ฉด ์ด๋ฐ๊ฒ ์๊ตฌ๋ ํ๊ณ ๋์ด๊ฐ์๊น. ์ด์จ๋ ์ง๊ธ์ ํ ์คํธ์๋ ๊ฐ๋ฐ์ด ๋ถ์ค๊ณต์ฌ๋ก ๋ณด์ธ๋ค. ๊ทธ๋ฐ ์ฝ๋๋ ๋นจ๋ฆฌ ์งํ๋๋ ๊ฒ ๊ฐ์๋ ํ๋ฒ ๋ฌด๋์ง๋ฉด ๊ฒ์ก์ ์ ์๊ฒ ๋๋ค. ํ ์คํธ์ ๋ฉ์ง์ ์๊ฒ ๋๊ณ ๋์๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ฑฐ๋ ๋ฆฌํฉํฐ๋ง ํ ๋ค์ ์ ์ฒด ํ ์คํธ๋ฅผ ๋๋ฆฌ๊ณ ์ด๋ก๋ถ์ด ์ผ์ฌ๋ถ๋ํ๊ฒ ์ผ์ง๋ ๊ฑธ ๋ณด๋ ์ฌ๋ฏธ๋ก ์ฝ๋๋ฅผ ์ง ๋ค. ๋ค์์ฅ์ ํ์ด๋ณด๋ ๋ง๋ง์น ์์ ๊ฒ ๊ฐ์๋ฐ ๋ค์์ฃผ๊ฐ ๊ธฐ๋๋๋ค.
๊ทธ๋ฆฌ๊ณ ํฌ์คํ ์ ๋ชฉ์ ์ํธ์๊ฒ ์ง๊ณ ์ถ์๋๋ฐ ์๋ฌด ์๊ฐ๋ ๋์ง ์์์ ์ด๋ชจ์ง๋ ๋ถ์๋ค. ํ ์คํธ์ ๋ฉ์ง์ด ์ ํด์ง๋ฉด ์ข๊ฒ ๋คโฆ