Grails / Groovy - 使用多个@TestMixin

时间:2011-10-26 13:47:28

标签: unit-testing grails mixins

在Grails中,我有一项服务,我想进行单元测试。该服务使用这些导入:

import grails.converters.JSON
import grails.web.JSONBuilder

我希望服务获取数据并将其转换为JSON:

def tables = DataProfileStats.withCriteria {
        projections {
            distinct("tableName")               
            }
        };

我编写的用于构建JSON的辅助方法是:

public String buildNodeString(String nodeText)
{
    def builder = new JSONBuilder();

    JSON result = builder.build {
        hello = "world"
        };

    return result.toString();
}

在单元测试中,我必须添加@TestMixin(ControllerUnitTestMixin),以便加载JSON适配器。但是我还要添加@TestMixin(DomainClassUnitTestMixin),这样我就可以模拟数据库对象了。

关于如何拥有多个@TestMixin的任何想法,或者这是一个设计问题,我在服务类中有一个导入grails.web.JSONBuilder?否则,我必须使用JAVA / JSON库或将JSON内容放在控制器中。

这就是我希望测试看起来像:

@TestMixin(ControllerUnitTestMixin)
@TestMixin(DomainClassUnitTestMixin)
class JsTreeJSONGeneratorServiceTests {

void testSomething() {

    DataProfileStats stats1 = new DataProfileStats();
    stats1.tableName = "table";

    mockDomain(DataProfileStats, stats1);

    JsTreeJSONGeneratorService service = new JsTreeJSONGeneratorService();
    String json = service.buildNodeString();
    assert json != "";

}

}

我得到了@TestMixin(ControllerUnitTestMixin) @TestMixin(DomainClassUnitTestMixin) class JsTreeJSONGeneratorServiceTests {

void testSomething() {

    DataProfileStats stats1 = new DataProfileStats();
    stats1.tableName = "table";

    mockDomain(DataProfileStats, stats1);

    JsTreeJSONGeneratorService service = new JsTreeJSONGeneratorService();
    String json = service.buildNodeString();
    assert json != "";

}

}

我得到了@TestMixin(ControllerUnitTestMixin) @TestMixin(DomainClassUnitTestMixin) class JsTreeJSONGeneratorServiceTests {

void testSomething() {

    DataProfileStats stats1 = new DataProfileStats();
    stats1.tableName = "table";

    mockDomain(DataProfileStats, stats1);

    JsTreeJSONGeneratorService service = new JsTreeJSONGeneratorService();
    String json = service.buildNodeString();
    assert json != "";

}

}

我得到一个“无法在同一个成员上指定重复注释:grails.test.mixin.TestMixin”异常。

由于

2 个答案:

答案 0 :(得分:20)

发现它!

@TestMixin([GrailsUnitTestMixin, ControllerUnitTestMixin, DomainClassUnitTestMixin])

答案 1 :(得分:0)

显然,这是由于Grails bug。在ControllerUnitTextMixin中混合的问题在于,它也会(和/或可能会)对服务无关或无用的许多逻辑,并且本质上是一种解决方法而不是修复。斯科特的答案绝对是稀疏和干净的,没有其他任何变化,但鉴于一些缺乏与Grails 2.0的向后兼容性,我会关注未来的版本,可能会强制逻辑进入setUp()方法这可能会破坏服务。

因此,为了完整起见,我将包括另一个直接从JIRA采取的潜在解决方法,全部归功于Ellery Crane:

package util.converters

import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationHolder
import org.codehaus.groovy.grails.web.converters.configuration.ConverterConfiguration
import org.codehaus.groovy.grails.web.converters.configuration.DefaultConverterConfiguration
import org.codehaus.groovy.grails.web.converters.marshaller.ObjectMarshaller
import org.codehaus.groovy.grails.web.converters.Converter
import org.codehaus.groovy.grails.web.converters.configuration.ChainedConverterConfiguration

class JSON extends grails.converters.JSON{

  public JSON(Object target) {
    super(target)
  }

  @Override
  protected ConverterConfiguration<grails.converters.JSON> initConfig() {    
    ConverterConfiguration config = super.initConfig()
    if(config.getOrderedObjectMarshallers().size() == 0){      
      initDefaultMarshallers()
      config = super.initConfig()
    }
    return config
  }

  private void initDefaultMarshallers(){
    List<ObjectMarshaller<grails.converters.JSON>> marshallers = new ArrayList<ObjectMarshaller<grails.converters.JSON>>();
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.ArrayMarshaller());
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.ByteArrayMarshaller());
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.CollectionMarshaller());
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.MapMarshaller());
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.EnumMarshaller());
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.ProxyUnwrappingMarshaller<grails.converters.JSON>());
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.DateMarshaller());
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.ToStringBeanMarshaller());

    boolean includeDomainVersion = true;
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.DomainClassMarshaller(includeDomainVersion));
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.GroovyBeanMarshaller());
    marshallers.add(new org.codehaus.groovy.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller());

    DefaultConverterConfiguration<grails.converters.JSON> cfg = new DefaultConverterConfiguration<grails.converters.JSON>(marshallers);
    cfg.setEncoding("UTF-8");
    cfg.setCircularReferenceBehaviour(Converter.CircularReferenceBehaviour.DEFAULT)
    cfg.setPrettyPrint(false);
    ConvertersConfigurationHolder.setDefaultConfiguration(grails.converters.JSON.class, new ChainedConverterConfiguration<grails.converters.JSON>(cfg));
  }
}

然后

  

只需导入util.converters.JSON而不是grails.converters.JSON,其他一切都可以无缝地工作。