java - Spock:Graphic2d 和 BuffredImage 的单元测试
问题描述
我在如何测试下面的类时遇到了困难。如何编写一个测试来检查图形是否以特定的宽度绘制“名称”,高度?以及我可以使用 spock 针对下面的类编写哪些其他测试。以及如何模拟异常?
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
}
}
解决方案
我不会说 Kotlin,但我稍微玩了一下你的类,只是添加了一个单独的构造函数,你可以在其中注入一个BufferedImage
. 只要你能做到这一点,你也可以注入一个模拟。如果您createGraphics()
在该模拟中存根以返回另一个Graphics2D
模拟,则可以轻松验证是否graphics.drawString(name, 300, 110)
以您期望的名称调用。
此外,没有必要捕获任何IOException
in,createNameCard()
因为toBase64()
您捕获了所有异常。因此,要么您完全删除createNameCard()
(变体 A)中的 try-catch,要么删除 中的 catch 子句toBase64()
,从而在调用方法(变体 B)中为您提供一些可捕获的内容。
无论如何,我会保留两个 catch 块,并向您展示如何为整个文件(包括错误案例)获得 100% 的测试覆盖率:
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
}
}
推荐阅读
- c# - 如何在 C# 和 C 中计算 CRC16-CCITT/KERMIT
- android - 如何修复android架构组件分页onItemAtEndLoaded进入循环?
- javascript - 如何在Javascript中获取数组[Array [{JSON}]]中元素的索引
- react-native - 在 React Native 中丢失互联网后如何重新连接 Hub?
- java - 在数据绑定布局中使用子组件时,如何让子组件正确编译?
- excel - Clas 变量声明不适用于 VBA 中的动态类加载,
- uml - 识别投票网络应用程序中的用例
- bash - 如何在shell中将变量转换为字符串
- javascript - setInterval/setTimeout 可能会导致页面重新加载
- vue.js - 发布到后端但请求始终为空(vue 到节点)