【问题标题】:Grails/Groovy - using multiple @TestMixinGrails/Groovy - 使用多个 @TestMixin
【发布时间】:2011-12-15 18:07:42
【问题描述】:

在 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) 类 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) 类 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”异常。

谢谢

【问题讨论】:

    标签: unit-testing grails mixins


    【解决方案1】:

    找到了!

    @TestMixin([GrailsUnitTestMixin, ControllerUnitTestMixin, DomainClassUnitTestMixin])
    

    【讨论】:

    • 祝贺解决方案。如果可以,请确保将您的答案标记为“已接受”,以便其他人可以从您的成功中学习。干杯~
    • 谢谢——这对我有帮助(不过我使用的是@Mock())。
    【解决方案2】:

    显然,这是由于Grails bug。与ControllerUnitTextMixin 混合的问题在于,它还做了(和/或可能会做)很多与服务无关或无用的逻辑,本质上是一种解决方法而不是修复。 Scott 的回答在没有进行其他更改的意义上肯定是稀疏和干净的,但鉴于某些缺乏与 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,其他一切都可以无缝运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-04
      • 1970-01-01
      相关资源
      最近更新 更多