Testing Service layer in Kotlin Spring Boot when back end is using Spring Security - spring-boot

I'm looking to try and test my back end Service layer (ideally along with my Controller layer too). However, I'm not sure how I would be able to go about doing this.
I saw that I can use Mockito to do this, however, I was not able to figure out how to apply this with what I currently have.
I have the entity, then repository, service and then finally controller.
My services have the main logic for the application within. For example, saving an entity, fetching and updating.
My controller (which is a restcontroller) is what my front end client interfaces with in order to call the service methods.
My service has an interface like below:
interface CompanyService {
fun saveCompany(company: Company): Company
fun saveCompany(form: CompanyController.SaveCompanyForm): Company
fun getCompany(name: String): Company
fun getCompany(id: Long): Company
fun getCompanies(): MutableList<Company>
fun addContactToCompany(firstName: String, lastName: String, companyName: String)
fun saveContact(contact: Contact): Contact
fun saveContact(form: CompanyController.SaveContactForm): Contact
fun saveContact(contact: Contact, companyName: String): Contact
fun getContact(firstName: String, lastName: String): Contact
fun getContact(id: Long): Contact
fun getContacts(): MutableList<Contact>
}
and then a CompanyServiceImpl:
#Service
#Transactional
class CompanyServiceImpl(
private val companyRepository: CompanyRepository,
private val contactRepository: ContactRepository,
) : CompanyService {
private val log = logger<CompanyServiceImpl>()
override fun saveCompany(company: Company): Company {
log.info("Saving Company ${company.name} to database")
return companyRepository.save(company)
}
...
}
My question as the subject says is how I would go about unit testing this so I don't have to manually do it which is both time consuming as well as it being "not the right way of doing it".
Ideally I'd like to have my controllers tested the same way, however I have Spring Security enabled and am unsure if this would get in the way in any way.

Related

Kotlin generics with Spring Events

I am trying to setup an event driven architecture on my Spring Application. I have an interface that blueprints all my processes and I have multiple #Components that inherited by that interface. The below is a simplification of my code:
interface Process<T: Any> {
val type: String
val name: String
fun complete(data: T)
fun cancel(data:T)
}
#Component
class MyProcess(prival val service) : Process<MyProcessDTO>
...
where
class MyProcessDTO {
val id: string
val isComplex: Boolean
}
The thing is that I have more than 10 beans than inherit from Process interface and each of them has a different *DTO type.
My idea would be to make a generic event from the given Process interface and publish the derived event types within each #Component. See my idea below :
class ProcessEvent<T: Process<T>> {
}
#Component
class MyProcess(private val service, val publisher: ApplicationEventPublisher) : Process<MyProcessDTO> {
fun publishEvent(myProcessEvent: ProcessEvent<MyProcessDTO>) {
this.service.makeRequest()
this.publisher.publish(myProcessEvent)
}
}
In that case MyProcess should publish a ProcessEvent with MyProcessDTO type.
Please note that the above is just an approximation of my goal.
Thanks

Using a custom ID in a Spring Data REST repository backed by MongoDB

I'm working on a new project using Spring and MongoDB. I'm a novice with both of these so bear with me, I couldn't find a definitive answer to this question.
I'm using spring-boot-starter-data-rest and have a repository like this:
#RepositoryRestResource(collectionResourceRel = "widget", path = "widget")
interface WidgetRepository : MongoRepository<Widget, ObjectId> {
fun findByType(#Param("type") type: String): List<Widget>
}
For an entity like this:
data class Widget #JsonCreator constructor(#JsonProperty val type: String) {
#Id
lateinit var id: ObjectId
}
This automatically gives you a CRUD API using the Mongo document ID:
GET /widget/{mongo doc id}
GET /widget/search/findByType?type=
POST /widget
PUT /widget
PATCH /widget
But I don't want to use the Mongo document ID. I want to introduce a secondary identifier and use that everywhere in the API. This is because the "widgets" are items in the physical world that are barcoded, and we don't want to print the Mongo document ID in the barcode.
Obviously we can implement this using Spring REST API tools, eg
#GetMapping("/widget/{barcode}/")
fun getByBarcode(#PathVariable barcode: String): Widget {
return widgetRepository.findByBarcode(barcode)
}
etc.. but is there any clever way to get #RepositoryRestResource to build its automagic API for us with a custom ID? Maybe by implementing CrudRepository<Widget, Barcode> in such a way that we have to wrap a MongoRepository<Widget, ObjectId> ? I'm not familiar enough with how Spring works under the hood to know if anything like this is even possible.
Thanks in advance
I think you are looking for an EntityLookup:
SPI to customize which property of an entity is used as unique identifier and how the entity instance is looked up from the backend.
First - sorry if I make any mistake, I do not use to program in Kotlin - you need to include the barcode property in your entity:
data class Widget #JsonCreator constructor(#JsonProperty val type: String, #JsonProperty val barcode: String) {
#Id
lateinit var id: ObjectId
}
Then, modify your repository and define a new method that will provide a Widget given its barcode:
#RepositoryRestResource(collectionResourceRel = "widget", path = "widget")
interface WidgetRepository : MongoRepository<Widget, ObjectId> {
fun findByBarcode(#Param("barcode") barcode: String): Optional<Widget>
fun findByType(#Param("type") type: String): List<Widget>
}
Finally, configure a RestRepositoryConfigurer and register the EntityLookup through an EntityLookupRegistrar:
#Component
class RestRepositoryConfigurator : RepositoryRestConfigurer {
override fun configureRepositoryRestConfiguration(config: RepositoryRestConfiguration) {
config.withEntityLookup()
.forRepository(WidgetRepository::class.java)
.withIdMapping(Widget::barcode)
.withLookup(WidgetRepository::findByBarcode)
}
}
Please, review the section 15.1 of the Spring Data Rest documentation if you need more information.

Using Service methods inside Utils class [Spring and Kotlin]

I have faced a well-known scenarios whereby I really need to move a number of utilities private functions (that should not have been there in the first place) from my Service class to a utility class. My question is around using service methods in a utility class. I have attempted at the following refactoring:
class Utils(
val serviceIneed : ServiceIneed) {
companion object {
private val someMapper = ObjectMapperConfig.mapper
}
fun someUtility(): ResponseEntity<Any> {
// lots of stuff
return serviceIneed.someFunction()
}
}
Then this is the other service where I need to use the method I have moved to the newly created utility class:
class anotherService(
private val serviceIneed: ServiceIneed
) {
fun someMethod() {
// lots of things happening
val utilityUsage = Utils(serviceIneed).someUtility()
}
}
Is this the correct way to go about this? Can you recommend any approach on refactoring service classes in a way that only service-oriented methods and not helper ones remain in my Service class?
Thank you

Updating a hibernate entity with CrudRepository

I'm currently writing my first spring boot Kotlin application and am trying to create a rest API with JPA persistence. The basics are going fine but I'm struggling with updating a model on a patch endpoint (#patchMapping).
I want to adhere to proper rest standards and for that reason I'm hitting the patch endpoint with #PatchMapping("/company/{id}").
I would like to be able to call the CrudRepository in a way like this.
#PatchMapping("/company/{id}")
fun update(#PathVariable id: Long, #RequestBody updateRequest: Company) : Company {
return repository.update(updateRequest, id)
}
but it appears as if the spring way to do it is to pass the id of the object you're going to update within the requestBody? e.g.
repository.save(updateRequest)
which then auto merges the object. But this conflicts with any sane rest convention...
is there an integrated solution available for what I want to achieve? I'd like to refrain from writing my own logic as I'd hoped spring to have this functionality.
Do you need something like this?
#RestController
class Controller(private val service: CompanyService) {
#PatchMapping("/company/{id}")
fun update(#PathVariable id: Long, #RequestBody company: Company): Company {
return service.updateCompany(company, id)
}
}
#Service
class CompanyService (private val repository: CompanyRepository) {
#Transactional
fun updateCompany(company: Company, id: Long): Company {
val companyToUpdate = repository.findOne(id)
companyToUpdate.setSomething(company.getSomething)
raturn companyToUpdate;
}
}
interface CompanyRepository : CrudRepository<Company, Long>

Return custom-typed object from JpaRepository

I have the following repository:
public interface UserRepository extends BaseDAO<User> {
Collection<User> findByEmail(#Param("email") String email);
#Query("select new com.data.CustomUser(upper(substring(u.lastName, 1, 1)) as initial, count(*)) from User u join u.chats c where c.business=:business group by upper(substring(u.lastName, 1, 1)) order by initial")
List<CustomUser> getContactsIndex(#Param("email") String email);
}
which is exposed with Spring Data REST. The User object is a managed entity, while CustomUser not and as you can see, it's build on-fly by using custom query.
Once I want to call that function, it fails with Persistent entity must not be a null! exception. Is there any way to implement this behavior?
P.S. Expose CustomUser with separate repository is impossible because it is not a managed entity.
One challenge with using Spring Data Rest is when you hit an edge case and you don't know whether you've hit a bug or whether you're just outside the scope of what the library is intended for. In this case I think you are at the edge of what SDR will easily do for you, and it's time to implement your own controller.
Spring Data Rest is looking for an Entity - in your case a User - as the return type for ALL methods in the repository to expose under /entities/search, and breaks when it doesn't find that entity type. The User it wants to serialize isn't there, hence the "Persistent entity must not be null".
The way around this is to write a simple #Controller that has a #RequestMapping for the exact same url exposed by the repository method. This will override the SDR generated implementation for that url, and from that you can return whatever you want.
Your implementation might look something like this:
#Controller
public class CustomUserController {
private final UserRepository repository;
#Inject
public CustomUserController(UserRepository repo) {
repository = repo;
}
#RequestMapping(value = "/users/search/getContactsIndex", method = GET, produces = {MediaType.APPLICATION_JSON_VALUE})
public #ResponseBody List<CustomUser> getContactsIndex(#RequestParam String email) {
return repository.getContactsIndex(email);
}
}
Be aware that there is a "recommended" way to override functionality this way. There is an open issue to document the best way to do this.

Resources