3

統合テストでコントローラーのアクションをテストしようとしています。これは、テストしようとしているアクションがサービスのメソッドを呼び出す単純なシナリオです。メタクラスを使用してそのメソッドをオーバーライドしようとしていますが、機能していないようです。つまり、メタクラスを使用してオーバーライドしたメソッドの代わりに、サービスの実際のメソッドが常に呼び出されます。ここで何が間違っていますか?

コントローラーのメソッドは次のとおりです。

class MyController {
  MyService myService

  def methodA() {
    def u = myService.find(params.paramA)
    render view: "profile", model:  [viewed: u]
  }

統合テストを実装する方法は次のとおりです。

class MyControllerTests extends GroovyTestCase {

 MyController controller

 void testMethodA() {
    controller = new MyController()

    // Mock the service
    MyService mockService = new MyService()
    mockService.getMetaClass().find = { String s ->
      []
    }

    controller = new MyController()
    controller.myService = myService

    controller.methodA()
  }

PS私はSTS 2.9.2でgrails 2.0.0を使用しています

4

2 に答える 2

7

まず最初に、Grailsとの統合に加えて、非常に優れたテストライブラリであるSpockFrameworkを使用することをお勧めします。テストは次のようになります。

@TestFor(MyController) // TestFor is builtin Grails annotation
class MyControllerSpec extends Specification {

    // thanks to TestFor annotation you already have 'controller' variable in scope

    MyService mockService = Mock(MyService)

    // setup method is executed before each test method (known as feature method)
    def setup() {
        controller.myService = mockService
    }

    def 'short description of feature being tested'() {
        given:
        mockService.find(_) >> [] // this tells mock to return empty list for any parameter passed

        when:
        controller.methodA()

        then:
        // here goes boolean statements (asserts), example:
        controller.response.text.contains 'Found no results'
    }
}

Spockを使用せずに滞在したい場合は、モックの場合、Groovy強制を使用するのが最も簡単な方法である必要があります。これをチェックしてください:

MyService mockService = [find: { String s -> [] }] as MyService

これはマップ強制です。あなたの場合、単一のメソッドをモックする場合、Mapさえ必要ないので、より簡単に書くことができます。

MyService mockService = { String s -> [] } as MyService

これは閉鎖強制です。さて、あなたがそれを扱っていないので、パラメータを指定することも必要ではありません。

MyService mockService = { [] } as MyService

最後のステートメントは基本的に、mockServiceで呼び出されたどのメソッドも指定されたクロージャーを実行することを意味するため、結果として空のリストが返されます。

シンプルな方がいいです、乾杯!

ちなみに、スポックを使用する場合でも、強制モックを使用できます。スポックモック(Mock()メソッドで作成)は、インタラクションなどのより高度なケースをテストするのに役立ちます。

更新:統合テストでは、IntegrationSpecを拡張し、@TestForを使用する必要はありません。

于 2012-12-20T17:28:00.017 に答える
1

ドキュメント10.1 Unit Testingから抜粋した次の例のように、Grails アノテーションを使用してサービスをモックすることをお勧めします。

@Mock([Book, Author, BookService])

次に、コントローラーのテストは次のようになります。

void testSearch() {
      def control = mockFor(SearchService)
      control.demand.searchWeb { String q -> ['mock results'] }
      control.demand.static.logResults { List results ->  }
      controller.searchService = control.createMock()
      controller.search()      assert controller.response.text.contains "Found 1 results"
}
于 2012-12-20T15:08:56.243 に答える