[Spring] Spring Boot로 ToDoApp만들기(투두 앱) (1)

728x90

  • 본 프로젝트는 테스트 주도 개발(Test-driven development, TDD)로 만들어짐
  • Repository 작성과 함께 테스트도 함께 작성함
  • 실제 데이터베이스는 사용X(JPA), 메모리DB사용

Config

AppConfig

// 스프링 부트 실행시, 해당 값들을 먼저 참조 -> Config Class
@Configuration
class AppConfig {

/*  val database = TodoDataBase()와 같은 형태로 static 걸어서 쓰지만
    Spring의 패러다임은 자동으로 주입되게 만드는 것임.*/

    @Bean(initMethod = "init")   // Bean으로 등록, init지정, 빈이 만들어질때 어떤 메소드 참조할지 정한다
    fun todoDataBase(): TodoDataBase {
        return TodoDataBase()
    }

}

 

 

DataBase

Todo

//Column
data class Todo(
    var index: Int? = null,                 // 일정 index
    var title: String? = null,              // 일정 title
    var description: String? = null,        // 일정 설명
    var schedule: LocalDateTime? = null,    // 일정 시간
    var createdAt: LocalDateTime? = null,   // 생성 시간
    var updatedAt: LocalDateTime? = null,   // 업데이트 시간
)

TodoDataBase

//Index
data class TodoDataBase(
    var index: Int = 0,
    var todoList: MutableList<Todo> = mutableListOf()
) {

    fun init() {
        this.index = 0
        this.todoList = mutableListOf() //초기화
        println("[DEBUG] todo database init")
    }
}


Repository

 

TodoRepository

interface TodoRepository {

    fun save(todo: Todo): Todo?
    fun saveAll(todoList: MutableList<Todo>): Boolean

    fun delete(index: Int): Boolean

    fun findOne(index: Int): Todo?
    fun findAll(): MutableList<Todo>

}

TodoRepositoryImpl

// TodoRepository 상속
@Service
class TodoRepositoryImpl : TodoRepository {

    @Autowired  // database init(Config)가 자동으로 주입됨, Autowired로 언제든지 접근 가능
    lateinit var todoDataBase: TodoDataBase

    override fun save(todo: Todo): Todo? {

        // 1. index?
        return todo.index?.let { index ->
            // update(값이 있을 때)
            findOne(index)?.apply {
                this.title = todo.title
                this.description = todo.description
                this.schedule = todo.schedule
                this.updatedAt = LocalDateTime.now()
            }
        } ?: kotlin.run {
            // insert(값이 없을 때)
            todo.apply {
                this.index = ++todoDataBase.index
                this.createdAt = LocalDateTime.now()
                this.updatedAt = LocalDateTime.now()
            }.run {
                todoDataBase.todoList.add(todo)
                this    // return
            }
        }
    }

    override fun saveAll(todoList: MutableList<Todo>): Boolean {
        return try {
            todoList.forEach {
                save(it)
            }
            true
        } catch (e: Exception) {
            false
        }
    }

//    override fun update(todo: Todo): Todo {
//        // jpa
//        // save db index -> 인덱스 있냐 업냐, 있으면 -> 업데이트, 없으면 -> insert
//    }

    override fun delete(index: Int): Boolean {

        return findOne(index)?.let {
            todoDataBase.todoList.remove(it)
            true    // 값이 있을 때
        } ?: kotlin.run {
            false   // 값이 없을 때
        }
    }

    override fun findOne(index: Int): Todo? {
        return todoDataBase.todoList.first { it.index == index }
    }

    override fun findAll(): MutableList<Todo> {
        return todoDataBase.todoList
    }
}

 

Test

TodoRepository

//TDD : Test만들면서 최소한의 코드를 코딩해 나간다

@ExtendWith(SpringExtension::class)
@SpringBootTest(classes = [TodoRepositoryImpl::class, AppConfig::class])  // 특정 클래스만 테스트(import), 효율적 테스트 위해, Bean도 불러와 준다
class TodoRepositoryTest {

    @Autowired
    lateinit var todoRepositoryImpl: TodoRepositoryImpl

    // Extension 기능 중 하나, 테스트가 실행되기 전에 무조건 실행됨
    @BeforeEach
    fun before() {
        todoRepositoryImpl.todoDataBase.init()
    }

    @Test
    fun saveTest() {
        val todo = Todo().apply {
            this.title = "테스트 일정"
            this.description = "테스트"
            this.schedule = LocalDateTime.now()
        }

        val result = todoRepositoryImpl.save(todo)

        // 자동으로 생성해주는 데이터베이스 값 Test -> Pass
        Assertions.assertEquals(1, result?.index)
        Assertions.assertNotNull(result?.createdAt)
        Assertions.assertNotNull(result?.updatedAt)
        Assertions.assertEquals("테스트 일정", result?.title)
        Assertions.assertEquals("테스트", result?.description)
    }

    @Test
    fun saveAllTest() {
        val todoList = mutableListOf(
            Todo().apply {
                this.title = "테스트 일정"
                this.description = "테스트"
                this.schedule = LocalDateTime.now()
            },
            Todo().apply {
                this.title = "테스트 일정"
                this.description = "테스트"
                this.schedule = LocalDateTime.now()
            },
            Todo().apply {
                this.title = "테스트 일정"
                this.description = "테스트"
                this.schedule = LocalDateTime.now()
            }
        )
        val result = todoRepositoryImpl.saveAll(todoList)

        Assertions.assertEquals(true, result)
    }

    @Test
    fun findOneTest() {
        println()
        val todoList = mutableListOf(
            Todo().apply {
                this.title = "테스트 일정1"
                this.description = "테스트"
                this.schedule = LocalDateTime.now()
            },
            Todo().apply {
                this.title = "테스트 일정2"
                this.description = "테스트"
                this.schedule = LocalDateTime.now()
            },
            Todo().apply {
                this.title = "테스트 일정3"
                this.description = "테스트"
                this.schedule = LocalDateTime.now()
            }
        )
        todoRepositoryImpl.saveAll(todoList)

        val result = todoRepositoryImpl.findOne(2)

        Assertions.assertNotNull(result)
        Assertions.assertEquals("테스트 일정2", result?.title)
    }

    @Test
    fun updateTest() {
        val todo = Todo().apply {
            this.title = "테스트 일정"
            this.description = "테스트"
            this.schedule = LocalDateTime.now()
        }
        val insertTodo = todoRepositoryImpl.save(todo)

        val newTodo = Todo().apply {
            this.index = insertTodo?.index
            this.title = "업데이트 일정"
            this.description = "업데이트 테스트"
            this.schedule = LocalDateTime.now()
        }

        val result = todoRepositoryImpl.save(newTodo)

        Assertions.assertNotNull(result)
        Assertions.assertEquals(insertTodo?.index, result?.index)
        Assertions.assertEquals("업데이트 일정", result?.title)
        Assertions.assertEquals("업데이트 테스트", result?.description)
    }
}
728x90

댓글

Designed by JB FACTORY