2016-08-22 20 views
8

Tôi đã phát triển một công cụ dòng lệnh gọi System.exit() (không muốn sử dụng ngoại lệ thay vì) trên một số đầu vào nhất định.Scala: Cách kiểm tra các phương thức gọi System.exit()?

Tôi quen thuộc với Java: How to test methods that call System.exit()? và thanh lịch nhất approach.

Thật không may, nó là không đủ tinh khiết, do tôi đã có thêm sự phụ thuộc vào system-rules, junit-interface

Có bất kỳ mô hình phổ biến để đối phó với System.exit trong specs2 đó là trong sạch hơn cách tiếp cận hiện tại của tôi mà không sử dụng thông số kỹ thuật2?

import org.junit.Rule; 
import org.junit.Test; 
import org.junit.contrib.java.lang.system.ExpectedSystemExit; 

public class ConverterTest { 
    @Rule 
    public final ExpectedSystemExit exit = ExpectedSystemExit.none(); 

    @Test 
    public void emptyArgs() { 
     exit.expectSystemExit(); 
     Converter.main(new String[]{}); 
    } 

    @Test 
    public void missingOutArgument() { 
     exit.expectSystemExitWithStatus(1); 
     Converter.main(new String[]{"--in", "src/test/resources/078.xml.gz"}); 
    } 
} 
+1

Kiểm tra https://groups.google.com/forum/#!topic/scalatest-users/pyKHtcP6HXM, trong đó Bill Venners (tác giả của ScalaTest) cung cấp câu trả lời hữu ích. –

Trả lời

6

Nếu bạn thực sự muốn đi với một phương pháp sử dụng System.exit(), cách đơn giản nhất để kiểm tra nó đã thực sự gọi là thay thế của bạn SecurityManager với một mà sẽ ném một ExitException (subclassing SecurityException) khi System.exit() được gọi là:

lớp SystemExitSpec

import java.security.Permission 

import org.specs2.mutable.Specification 
import org.specs2.specification.BeforeAfterAll 

sealed case class ExitException(status: Int) extends SecurityException("System.exit() is not allowed") { 
} 

sealed class NoExitSecurityManager extends SecurityManager { 
    override def checkPermission(perm: Permission): Unit = {} 

    override def checkPermission(perm: Permission, context: Object): Unit = {} 

    override def checkExit(status: Int): Unit = { 
    super.checkExit(status) 
    throw ExitException(status) 
    } 
} 


abstract class SystemExitSpec extends Specification with BeforeAfterAll { 

    sequential 

    override def beforeAll(): Unit = System.setSecurityManager(new NoExitSecurityManager()) 

    override def afterAll(): Unit = System.setSecurityManager(null) 
} 

kiểm tra ConverterSpec

import org.specs2.execute.Failure 

import scala.io.Source 

class ConverterSpec extends SystemExitSpec { 

"ConverterSpec" should { 

    "empty args" >> { 
     try { 
     Converter.main(Array[String]()) 
     Failure("shouldn't read this code") 
     } catch { 
     case e: ExitException => 
      e.status must_== 1 
     } 
     1 must_== 1 
    } 
} 
+0

Tôi có thể đã bỏ lỡ phần này, tuy nhiên, sẽ tốt hơn nếu có 'myObject .myFunctionExiting() phải throwAn (ExitException (1)) ' –

+0

Tôi xấu ở thông số kỹ thuật 2. đã hoàn thành! – Ven

+0

xin lỗi vì một mớ hỗn độn, bạn nên hoàn nguyên thay đổi cuối cùng của mình, chúng tôi phải sử dụng mệnh đề của bạn, tại sao? xác minh status.code, do [triển khai] (https://github.com/etorreborre/specs2/blob/master/matcher/src/main/scala/org/sp ecs2/matcher/ExceptionMatchers.scala # L47) –

0

Tùy chọn đầu tiên: sử dụng một số ngoại lệ thay vì System.exit.

Tùy chọn thứ hai: gọi ứng dụng trong chuỗi riêng biệt và kiểm tra mã trả lại.

Tùy chọn thứ ba: giả System.exit. Có rất nhiều khả năng để làm điều đó, đề cập đến một là khá tốt.

Tuy nhiên, không có specs2 mẫu cụ thể để làm việc với System.exit. Cá nhân tôi muốn đề xuất các tùy chọn đầu tiên hoặc thứ hai.

+0

1. Tùy chọn đầu tiên không được chấp nhận đối với tôi. 2. Tùy chọn thứ hai được thiết kế quá mức với tôi và phức tạp hơn ** quy tắc hệ thống ** 3. Tùy chọn thứ ba - giống như trước IMO, sử dụng ** quy tắc hệ thống ** là ngắn gọn, ngoại trừ nó không sử dụng ** specs2 ** :( –

+1

Đối với tùy chọn thứ ba, bạn có thể sử dụng thư viện nhại có thể giả lập các lớp tĩnh, ví dụ: PowerMock. – dveim

Các vấn đề liên quan