4

In my play application i intend to mock a case class. I am able to do so but it creates an object with all member variables null. Is there a way to create mock objects of a case classes such that the object can have some members initialized?

case class User(name: String, address: String)    
val mockUser = mock[User]
user.name // null
user.address //null

how do i create a mockUser such that i can assign some values to name and address?

Edit:

I need the ability to mock the object because i want to have predefined behavior of one of the member method. (This member method calls an external service and i dont want the external service call while doing a unit test.) The member method is called inside another member method, which i want to test.

konquestor
  • 1,308
  • 3
  • 15
  • 29
  • Is it really useful to mock case classes? Instead of creating test instances with fake values? – cchantep May 12 '16 at 10:46
  • i need a mock , because i dont want certain methods of the class to be not executed, instead i want a predefined behavior. question updated. – konquestor May 12 '16 at 11:21

3 Answers3

22

It should be as simple as this:

when(mockUser.name).thenReturn("Bob")

As far as:

You should never need to mock case classes. It's like "mocking an integer".

False. (IMHO)

What's wrong with val mockUser = User("mockName", "mockAddress")?

Nothing if you dont think there's anything wrong with

val mockFoo = FooWith20Properties("1", "2", "3",..."20")

Your tests will work but you've missed the point of using a mocking framework to reduce your test boilerplate.

Having said that there does seem to be a divide between those that think case classes should be final and those that dont. If you mark yours final then mocking wont work without resorting to something equally controversial such as Powermock.

Nick
  • 8,181
  • 4
  • 38
  • 63
  • 1
    You can write helper functions for factoring out test boilerplate when creating objects. No need for mocking. And if you have to create many irrelevant values that aren't used, it's a sign that your data might benefit from refactoring. – Gary Coady Apr 23 '18 at 11:19
7

You should never need to mock case classes. It's like "mocking an integer".

What's wrong with val mockUser = User("mockName", "mockAddress")?

Dima
  • 39,570
  • 6
  • 44
  • 70
  • 1
    I need the ability to mock the object because i want to have predefined behavior of one of the member method. (This member method calls an external service and i dont want the external service call while doing a unit test.) The member method is called inside another member method, which i want to test. – konquestor May 12 '16 at 11:25
  • 7
    There is so much wrong with this design, I don't even know where to start. You should not be mocking case classes ... Case classes should not be calling external services ... You should not be mocking objects you are testing ... Calls to exteral services should be isolated, so that you can stub them out by themselves ... But, at a more basic level, how in the world are you planning to "test a member method" on an object that you _just mocked_??? – Dima May 12 '16 at 13:23
0

I would move your external service call out of the case class, into a service class and then mock this service class.

Usually, case classes represent data. It leads to neater code if data and the functions which use that data (e.g. your external call) are separate.

I would write code like

case class User(name: String, address: String)

class UserService {
  def callExternalService(user: User): Result = ???
}

val testUser = User("somebody", "somewhere")
val mockService = mock[UserService]
when(mockService.callExternalService(testUser)).thenReturn(...)