Reputation: 83
I am having a difficulty how to test the below class.How Can I write a test which checks whether graphics draw "name" or not with specific width ,heigh ?And what other tests I can write against the following class using spock. And How Can I mock the exception?
class NameCardCreator{
private val bufferedImage = BufferedImage(580, 380, BufferedImage.TYPE_INT_ARGB)
var name: String? = null
const val DISCLAIMER = "Name is Correct"
fun createNameCard(): String?
{
var generic64: String? = null
try {
dashed = BasicStroke(3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0f, floatArrayOf(5f), 0f)
val graphics = bufferedImage.createGraphics()
graphics.drawRoundRect(20, 20, 535, 340, 15, 15) //actual card size
val fontMetrics = graphics.fontMetrics
graphics.drawLine(300, 120, 540, 120)
if (!name.isNullOrEmpty()) {
graphics.drawString(name, 300, 110)
}
graphics.drawString(DISCLAIMER, 50, 290)
generic64 = toBase64(bufferedImage)
return generic64
} catch (ie: IOException) {
logger.info("Name card could not be generated $ie.message")
}
return generic64
}
protected fun toBase64(bufferedImage: BufferedImage): String? {
var base64Str: String? = null
var os: ByteArrayOutputStream? = null
var b64: OutputStream? = null
try {
os = ByteArrayOutputStream()
b64 = Base64OutputStream(os)
ImageIO.write(bufferedImage, "png", b64)
base64Str = os.toString("UTF-8")
} catch (e: Exception) {
logger.error(e.message)
} finally {
os?.close()
b64?.close()
}
return base64Str
}
}
Upvotes: 0
Views: 247
Reputation: 67457
I do not speak Kotlin, but I played around with your class a little bit and just added a separate constructor in which you can inject a BufferedImage
. As soon as you can do that, you also can inject a mock. If you stub createGraphics()
in that mock to return yet another Graphics2D
mock, you can easily verify if graphics.drawString(name, 300, 110)
was called with the name you expect.
Besides, there is no need to catch any IOException
in createNameCard()
because in toBase64()
you catch all exceptions. So either you completely remove the try-catch in createNameCard()
(variant A) or you remove the catch clause in toBase64()
, giving you something to catch in the calling method (variant B).
Anyway, I am keeping both catch blocks and am showing you how to get 100% test coverage for the whole file including the error cases:
package de.scrum_master.testing.kotlin
import org.apache.commons.codec.binary.Base64OutputStream
import java.awt.BasicStroke
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.OutputStream
import javax.imageio.ImageIO
class NameCardCreator {
private var bufferedImage = BufferedImage(580, 380, BufferedImage.TYPE_INT_ARGB)
private var name: String? = null
val DISCLAIMER = "Name is Correct"
constructor()
constructor(name: String?) {
this.name = name
}
constructor(bufferedImage: BufferedImage, name: String?) {
this.bufferedImage = bufferedImage
this.name = name
}
fun createNameCard(): String? {
var generic64: String? = null
try {
val dashed = BasicStroke(3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0f, floatArrayOf(5f), 0f)
val graphics = bufferedImage.createGraphics()
graphics.drawRoundRect(20, 20, 535, 340, 15, 15) // actual card size
val fontMetrics = graphics.fontMetrics
graphics.drawLine(300, 120, 540, 120)
if (!name.isNullOrEmpty()) {
graphics.drawString(name, 300, 110)
}
graphics.drawString(DISCLAIMER, 50, 290)
generic64 = toBase64(bufferedImage)
return generic64
} catch (ie: IOException) {
println("Name card could not be generated: $ie.message")
}
return generic64
}
protected fun toBase64(bufferedImage: BufferedImage): String? {
var base64Str: String? = null
var os: ByteArrayOutputStream? = null
var b64: OutputStream? = null
try {
os = ByteArrayOutputStream()
b64 = Base64OutputStream(os)
ImageIO.write(bufferedImage, "png", b64)
base64Str = os.toString("UTF-8")
} catch (e: Exception) {
println("Base64 encoding failed: $e.message")
} finally {
os?.close()
b64?.close()
}
return base64Str
}
}
package de.scrum_master.testing.kotlin
import org.apache.commons.codec.binary.Base64
import spock.lang.Specification
import javax.imageio.ImageIO
import java.awt.*
import java.awt.image.BufferedImage
class NameCardCreatorTest extends Specification {
def "check that base64 actually encodes an image"() {
given:
def nameCardCreator = new NameCardCreator("John Doe")
when:
def imageBase64 = nameCardCreator.createNameCard()
// println imageBase64
def imageBytes = new Base64().decode(imageBase64)
// new FileOutputStream("name-card.png").write(imageBytes)
def bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes))
then:
bufferedImage.width == 580
bufferedImage.height == 380
}
def "check that name was written on card"() {
given:
def graphics2D = Mock(Graphics2D)
def bufferedImage = Mock(BufferedImage) {
// Return Graphics2D mock
createGraphics() >> graphics2D
}
when:
new NameCardCreator(bufferedImage, "John Doe").createNameCard()
then:
1 * graphics2D.drawString("John Doe", _, _)
}
def "exception during card creation leads to null result"() {
given:
def bufferedImage = Mock(BufferedImage) {
// Throw an exception for each method call
_(*_) >> { throw new IOException("uh-oh") }
}
expect:
new NameCardCreator(bufferedImage, "John Doe").createNameCard() == null
}
def "exception during base64 encoding leads to null result"() {
given:
def bufferedImage = Mock(BufferedImage) {
// Throw an exception for each method call
_(*_) >> { throw new IOException("uh-oh") }
}
expect:
new NameCardCreator().toBase64(bufferedImage) == null
}
}
Upvotes: 1