当单元测试方法具有断言而不是异常时,最佳实践是什么?
What is the best practice when unit testing methods that have assertions instead of exceptions?
假设您有一个像这样的public方法
public Sprite spriteAt(int x, int y)
{
assert withinBorders(x, y) : "PRE: x and y should be inside the borders";
return tileAt(x, y).topSprite();
}
对
public Sprite spriteAt(int x, int y)
{
if (!withinBorders(x, y)) throw new InvalidArgumentException();
return tileAt(x, y).topSprite();
}
在最底下的情况下,我通常会有一个单元测试用例来检查当给出 x and/or y 的无效值时是否抛出异常,例如:
@Test(expected = InvalidArgumentException.class)
public void SpriteAt_InvalidX_ThrowsInvalidArgumentException()
{
sut.spriteAt(-100, 0);
}
此测试用例是为了确保在方法中实现参数验证逻辑。
但是,对于顶部的断言方法,我不确定我应该做什么。断言不是生产代码,我认为这意味着我不必测试断言。
另一方面,我认为当方法中的逻辑发生变化时,单元测试应该通过失败来通知开发人员。如果我不编写测试用例来检查是否存在检查无效参数的断言(就像我对异常方法所做的那样),那么当我不小心删除断言代码行时,我可能不会意识到我犯了一个错误。
因此,如果 junit 运行 启用了断言,我想做的是检查断言是否到位,并且在断言未启用时不做任何事情。下面的代码将包含伪代码。
@Test
public void SpriteAt_InvalidX_AssertionThrowsException()
{
if (assertion is enabled)
{
try
{
sut.spriteAt(-100, 0);
fail();
}
catch (AssertionFailureException e)
{
}
}
}
回到我的观点。我想知道单元测试是否应该测试断言。如果是这样,我会朝着正确的方向前进吗?如果不是,您如何防止在没有单元测试的情况下意外删除断言代码?
有趣的问题。
在我看来,如果你想要测试 x
或 y
明确不在范围内的情况,那么你应该抛出 IllegalArgumentException
而不是使用 assert
。另一方面,您没有方法注释 告诉 此方法的调用者 x
或 y
必须在一个范围内。因此,如果您从调用者的角度来看它,您根本无权断言这一点。 :-p
我会使用 assert
来检查我没有单元测试的前提条件。但另一方面,您应该对该示例进行单元测试。
在一天结束时 assert
也会抛出 RuntimeException
并且 - 正如您所说 - 仅在开发期间编译器标志是那个。那么,为什么不简单地使用 IllegalArgumentException
呢,它看起来很适合这种情况。并且请给方法的调用者一个提示,在这种情况下会用 @throws
注释抛出。
我的结论:只要单元测试覆盖率良好,assert
就毫无用处。 仅适用于开发期间的手动测试 以检查您不需要的前置条件或可以为其编写明确的单元测试。
如果您使用 -ea
java 命令参数打开 assert
功能,您始终可以测试它。
assert
抛出 java.lang.AssertionError
.
单元测试应该测试行为,而不是实现。因此,如果合同 (JavaDoc) 中未明确定义断言行为,则不应对其进行测试。
assert
非常无用,几乎从未在实际系统中使用过。
假设您有一个像这样的public方法
public Sprite spriteAt(int x, int y)
{
assert withinBorders(x, y) : "PRE: x and y should be inside the borders";
return tileAt(x, y).topSprite();
}
对
public Sprite spriteAt(int x, int y)
{
if (!withinBorders(x, y)) throw new InvalidArgumentException();
return tileAt(x, y).topSprite();
}
在最底下的情况下,我通常会有一个单元测试用例来检查当给出 x and/or y 的无效值时是否抛出异常,例如:
@Test(expected = InvalidArgumentException.class)
public void SpriteAt_InvalidX_ThrowsInvalidArgumentException()
{
sut.spriteAt(-100, 0);
}
此测试用例是为了确保在方法中实现参数验证逻辑。
但是,对于顶部的断言方法,我不确定我应该做什么。断言不是生产代码,我认为这意味着我不必测试断言。
另一方面,我认为当方法中的逻辑发生变化时,单元测试应该通过失败来通知开发人员。如果我不编写测试用例来检查是否存在检查无效参数的断言(就像我对异常方法所做的那样),那么当我不小心删除断言代码行时,我可能不会意识到我犯了一个错误。
因此,如果 junit 运行 启用了断言,我想做的是检查断言是否到位,并且在断言未启用时不做任何事情。下面的代码将包含伪代码。
@Test
public void SpriteAt_InvalidX_AssertionThrowsException()
{
if (assertion is enabled)
{
try
{
sut.spriteAt(-100, 0);
fail();
}
catch (AssertionFailureException e)
{
}
}
}
回到我的观点。我想知道单元测试是否应该测试断言。如果是这样,我会朝着正确的方向前进吗?如果不是,您如何防止在没有单元测试的情况下意外删除断言代码?
有趣的问题。
在我看来,如果你想要测试 x
或 y
明确不在范围内的情况,那么你应该抛出 IllegalArgumentException
而不是使用 assert
。另一方面,您没有方法注释 告诉 此方法的调用者 x
或 y
必须在一个范围内。因此,如果您从调用者的角度来看它,您根本无权断言这一点。 :-p
我会使用 assert
来检查我没有单元测试的前提条件。但另一方面,您应该对该示例进行单元测试。
在一天结束时 assert
也会抛出 RuntimeException
并且 - 正如您所说 - 仅在开发期间编译器标志是那个。那么,为什么不简单地使用 IllegalArgumentException
呢,它看起来很适合这种情况。并且请给方法的调用者一个提示,在这种情况下会用 @throws
注释抛出。
我的结论:只要单元测试覆盖率良好,assert
就毫无用处。 仅适用于开发期间的手动测试 以检查您不需要的前置条件或可以为其编写明确的单元测试。
如果您使用 -ea
java 命令参数打开 assert
功能,您始终可以测试它。
assert
抛出 java.lang.AssertionError
.
单元测试应该测试行为,而不是实现。因此,如果合同 (JavaDoc) 中未明确定义断言行为,则不应对其进行测试。
assert
非常无用,几乎从未在实际系统中使用过。