0

The question I have is simple and straightforward

Let's say I have this function which returns a random string

fun generateRandomId(): String {
    val randomString = UUID.randomUUID().toString().replace("-", "")
    return randomString
}

And I wanna test the above function using JUnit

@Test
fun generateRandomId() {
    Assertions.assertEquals()
}

Not sure how to assert that the randomly generated String doesn't have any "-".

capt.swag
  • 9,754
  • 2
  • 38
  • 38
  • 1
    How could it *not* be a string? In any case, if you want to test the return *type*, then check the type. It can't return anything *other* than a `String`, though, so this seems non-sensical--Kotlin is statically-typed. – Dave Newton Jul 17 '20 at 13:38
  • @DaveNewton Yes, I think I should test the return type. I would agree that for a statically typed language like Kotlin this test wouldn't be required, but I was going for 100% test coverage on this file. – capt.swag Jul 17 '20 at 13:46
  • @DaveNewton I've update the question now to make it more interesting – capt.swag Jul 17 '20 at 13:48
  • `assertFalse(generateRandomId().contains("-"))` – Gustavo Jul 17 '20 at 13:50
  • Oh, yes. That was easy, didn't think about that. – capt.swag Jul 17 '20 at 13:51
  • 1
    Testing the return type is testing the Kotlin language itself. That's not the point of unit testing, and it provides no value to your test suite. – Dave Newton Jul 17 '20 at 14:02
  • Agreed @DaveNewton – capt.swag Jul 17 '20 at 14:03
  • 1
    To check it's random: call it twice, and assert that the results differ? – gidds Jul 17 '20 at 14:55
  • Good one @gidds – capt.swag Jul 17 '20 at 15:37
  • (Of course, there's a very very tiny probability that you could genuinely get the same result twice running.  But if the domain is large enough, that can be small enough not to worry about.) – gidds Jul 17 '20 at 16:01

1 Answers1

1
assertFalse(generateRandomId().contains("-"))

Previous answer to the original question:

If the function uses another class to generate the random String, then inject that other class in the constructor of your class:

class MyClass(someOtherClass: SomeOtherClass) {


    fun generateRandomId(): String {
        val randomString = someOtherClass.generateRandom()
        return randomString
    }
}

and in your tests you mock SomeOtherClass and all you need to do is to check that whatever SomeOtherClass returns, is returned in your function.

@Test
fun testGenerateRandomId() {
   // given
   val someOtherClassMock: SomeOtherClass = mock() // 1
   val myClass = MyClass(someOtherClassMock) // 2
   val randomString = "randomString"
   whenever(someOtherClassMock.generateRandom()).thenReturn(randomString) // 3

   // when
   val result = myClass.generateRandomId()

   // then
   assertEquals(randomString, result)
}

1 and 3: mock the behaviour of SomeOtherClass with your preferred mocking framework / fake implementation

1 and 2: these lines usually go in the setUp method of your test class


Now if you don't use an external class to generate your random String, you will have to paste your code for further help.

Gustavo
  • 5,586
  • 5
  • 38
  • 68
  • I actually thought about it. But random number generation is done by a static function. So can't really mock anything in this circumstance. I could certainly use a wrapper. But I would like to have a solution where JUnit can do something like assertString(). – capt.swag Jul 17 '20 at 13:44
  • 1
    wrapper would be my recommendation for this situation, but you can use mock frameworks that mock static methods, which I don't recommend. for more info check [this](https://stackoverflow.com/questions/21105403/mocking-static-methods-with-mockito) – Gustavo Jul 17 '20 at 13:47