Groovy Testing

16 March 2016

My previous post is all about writing a simple Groovy CRUD application. It includes writing your views in Groovy as well though it doesn't involve where to put the files. But if you're a seasoned Java developer, you should know your way out.

What it lacks is how to test your Groovy classes which I'm about to document on this post.

FakeLoader

This is a workaround assuming your Spring Boot application bootstraps more @Configuration and you don't want to include them in your integration tests.

import org.junit.Test
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.test.context.ActiveProfiles

/**
 * For integration tests
 */
@ActiveProfiles("dev")
@SpringBootApplication
class FakeLoader {

}

Repository integration test

package com.manalo.repository

import com.manalo.FakeLoader
import com.manalo.config.HttpSessionConfig
import com.manalo.domain.User
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.SpringApplicationConfiguration
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.web.WebAppConfiguration
import spock.lang.Specification

@ActiveProfiles("dev")
@SpringApplicationConfiguration(classes = FakeLoader)
@WebAppConfiguration
class UserRepositorySpec extends Specification{

    @Autowired
    UserRepository userRepository

    User user

    def setup() {
        user = new User(id: 1, username: "admin", password: "secret")
    }

    def "Should save user"() {

        when: "save is invoked"
        userRepository.save(user)

        then: "user saved and searchable"
        User actual = userRepository.findOne(1)
        actual.getId() == 1
        actual.getUsername() == "admin"
        actual.getPassword() == "secret"
    }

    def "Should edit user"() {

        String username = "updated user"
        String password = "updated password"

        when: "update is invoked"
        user.setUsername(username)
        user.setPassword(password)
        userRepository.save(user)

        then: "user updated and searchable"
        User actual = userRepository.findOne(1)
        actual.getId() == 1
        actual.getUsername() == username
        actual.getPassword() == password
    }

    def "Should delete user"() {

        when: "user is invoked"
        userRepository.delete(user)

        then: "user deleted and not searchable"
        User actual = userRepository.findOne(1)
        assert actual == null
    }
}

Service layer test

package com.manalo.controller

import com.manalo.domain.User
import com.manalo.repository.UserRepository
import com.manalo.service.UserService
import spock.lang.Specification

class UserServiceSpec extends Specification {

    UserService userService
    UserRepository userRepository = Mock(UserRepository)

    final Integer userId = 1

    def setup() {
        userService = new UserService(userRepository: userRepository)
    }

    def "Should find all users"() {

        when: "the users are retrieved"
        userService.list()

        then: "a list of users is returned"
        1 * userRepository.findAll()
    }

    def "Should find by id"() {

        when: "looking for user.id $userId"
        userService.findById(userId)

        then: "user.id $userId is found"
        1 * userRepository.findOne(userId)
    }

    def "Should save a user"() {

        given: "a new user"
        User user = new User()

        when: "save is invoked"
        userService.save(user)

        then: "user is saved"
        1 * userRepository.save(user)
    }

    def "Should update existing user"() {

        given: "an existing user"
        User user = new User()
        user.id = userId
        userRepository.findOne(userId) >> user

        when: "save is invoked"
        userService.save(user)

        then: "user is saved"
        1 * userRepository.save(user)
    }

    def "Should delete existing user"() {

        given: "an existing user"
        User user = new User()
        user.id = userId
        userRepository.findOne(userId) >> user

        when: "delete is invoked"
        userService.delete(user)

        then: "user is deleted"
        1 * userRepository.delete(user)
    }
}

Controller test

package com.manalo.controller

import com.manalo.domain.User
import com.manalo.service.UserService
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Specification

import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*

class UserControllerSpec extends Specification {

    MockMvc mockMvc
    UserService userService = Mock(UserService)

    def setup() {
        def controller = new UserController(userService: userService)
        mockMvc = standaloneSetup(controller).build()
    }

    def "should return list of users"() {

        given:
        final String userList = "/user/list"

        when:
        "requesting $userList"
        def response = mockMvc.perform(get(userList))

        then: "receive 200"
        response.andExpect(status().isOk())
        1 * userService.list()
    }

    def "should load screen for adding new user"() {

        given:
        final String userAdd = "/user/add"

        when:
        "requesting $userAdd"
        def response = mockMvc.perform((get(userAdd)))

        then: "receive 200"
        response.andExpect(status().isOk())
                .andExpect(view().name("views/user/edit"))
    }

    def "should load screen for editing user"() {

        given:
        final String userEdit = "/user/1"

        when:
        "requesting $userEdit"
        def response = mockMvc.perform((get(userEdit)))

        then: "receive 200"
        response.andExpect(status().isOk())
                .andExpect(view().name("views/user/edit"))
        1 * userService.findById(1)
    }

    def "should redirect after save"() {

        given:
        final String userSave = "/user/save"

        when:
        "requesting $userSave"
        def response = mockMvc.perform((post(userSave)))

        then: "receive 302"
        response.andExpect(status().is3xxRedirection())
                .andExpect(view().name("redirect:/user/list"))
    }

    def "should delete existing user"() {

        given:
        final String userDelete = "/user/delete"

        when:
        "requesting $userDelete"
        def response = mockMvc.perform(post(userDelete))

        then: "receive 302"
        response.andExpect(status().is3xxRedirection())
                .andExpect(view().name("redirect:/user/list"))
    }


}