伙计我是JUnit测试的新手,并试图抓住它,现在我正在为构造函数(对于创建有向图的Digraph类)编写JUnit测试,当它读取负int值时会抛出IllegalArgumentException如果一切正常(节点值的数量)大于零,则创建一个图形。
有向图类:
In in = new In();
public Digraph(In in) {
try {
this.nodes = in.readInt();
System.out.println("Total nodes in graph: "+ nodes);
if (nodes < 0) throw new IllegalArgumentException("Number of vertices must be > 0);
int E = in.readInt();
if (E < 0) throw new IllegalArgumentException("Number of edges must be >0);
}catch (NoSuchElementException e) {
throw new InputMismatchException("Invalid input format in Digraph constructor");
}
以下是我要写的测试:
@Rule
public ExpectedException exception = ExpectedException.none();
@Test(expected = IllegalArgumentException.class)
public void DigraphIn() {
Digraph G = new Digraph(in.readInt());
exception.expect(IllegalArgumentException.class);
exception.expectMessage("Vertices can't be nagative");
exception.expectMessage("Invalid input format in Digraph constructor");
exception.expectMessage("Number of edges in a Digraph must be nonnegative");
try{
}catch (AssertionError e){
}
}
如何使用一个(或两个)测试用例测试这两种情况?如果“in”中没有检测到-ve值,我会得到java.lang.AssertionError,否则测试通过。提前致谢
答案 0 :(得分:2)
你应该有很多测试用例。 每个例外都有一个很好。
您执行的每项测试都是不同的,应该区别对待。
一个很好的参考是:Junit Cookbook。
实际上我在代码中看到了一个错误。 在您的测试用例中,您可以嘲笑协作者,如下所示。我做了一个模拟,使用'mockito'模拟库在每个调用返回不同的值。
你基本上需要这样的东西:
@Test(expected = IllegalArgumentException.class)
public void DigraphInThatThrowsExceptionForVertices() {
In in = Mockito.mock(In.class);
when(in.readInt()).thenReturn(-1);
Digraph G = new Digraph(in);
fail();
}
@Test(expected = IllegalArgumentException.class)
public void DigraphInThatThrowsExceptionForEdges() {
In in = Mockito.mock(In.class);
when(in.readInt()).thenReturn(10).thenReturn(-1);
Digraph G = new Digraph(in);
fail();
}
@Test
public void DigraphInThatDoesNotThrowException() {
In in = Mockito.mock(In.class);
when(in.readInt()).thenReturn(10).thenReturn(15);
Digraph G = new Digraph(in.readInt());
}
这样,测试代码更简洁易读。
答案 1 :(得分:1)
当你测试一个实际调用它的方法时,它将使它执行。测试只能验证每个测试的一个异常,因为异常将取消该方法的其余处理。因此,您需要为可以抛出异常的每个位置进行一次测试。
在验证单元测试引发异常时,基本上有3种方法可以执行此操作:
try-catch块:
@Test
public void myTest() {
try {
myClass.myMethod(42);
fail();
} catch(final IllegalArgumentException e) {
assertEquals("something went wrong", e.getMessage());
}
}
expected
- 注释的@Test
- 属性:
@Test(expected=IllegalArgumentException.class)
public void myTest() {
myClass.myMethod(42);
}
和ExpectedException
:
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void myTest() {
expectedException.expect(IllegalArgument.class);
expectedException.expectMessage("something went wrong");
myClass.myMethod(42);
}
在你的例子中,你试图使用这三个。
如果我们比较测试异常的方法,只有第一个和第三个实际上能够对抛出的异常进行验证,这使得它们更适用于可以从多个位置抛出相同类型的异常的测试方法,然后,您可以使用异常消息来验证是否从您所在的位置抛出了异常。
第二个是迄今为止最具可读性的,但是不允许您区分被测方法抛出的异常,在大多数情况下它没有提供与其他两个一样多的值。
在第一个和第三个中,第三个是迄今为止最具可读性的,也是我个人的最爱。
由于测试中的方法每次执行只能抛出一个异常,因此对于每个可能引发异常的地方都应该有一个测试方法:
public class DiagraphTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
private Diagraph diagraph;
private In in;
@Before
public void setup() {
in = mock(In.class);
}
@Test
public void constructorShouldThrowExceptionWhenNumberOfVerticesIsLessThanOne() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("vertices must be > 0"); //expectMessage only needs a substring of the exception-message
doReturn(-1).when(in).readInt();
new Diagraph(in);
}
@Test
public void constructorShouldThrowExceptionWhenNumberOfEdgesIsLessThanOne() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("edges must be > 0");
when(in.readInt()).thenReturn(42, -1);
new Diagraph(in);
}
//as to the last exception, I really can't see that it will ever be thrown in that try-block, but here's a test for that as well..
@Test
public void constructorShouldThrowInputMismatchExceptionIfReceivedNoSuchElementException() {
expectedException.expect(InputMismatchException.class);
expectedException.expectMessage("Invalid input format);
doThrow(new NoSuchElementException("phail")).when(in).readInt();
new Diagraph(in);
}
}