访问Groovy中另一个函数中定义的变量

时间:2018-08-14 21:00:10

标签: groovy

我是Groovy的新手。 我有一个函数,可以在其中写入要映射的值。

def addTraceEntry(key, value) {
    def traceability = [:]
    traceability[key] = value.trim()
    println "This print happens in function addTraceEntry " + traceability
    }

我还有另一个功能,需要验证以上功能是否正常工作。

def testAddTraceEntry() {
    def key = 'test_key'
    def value = 'test_value'
    addTraceEntry(key, value)
    println "This print happens in function testAddTraceEntry " + traceability
    assert value == traceability[key]
}

我正在使用函数名称调用testAddTraceEntry()函数:

testAddTraceEntry()

运行此命令时,出现错误:

This print happens in function addTraceEntry [test_key:test_value]
Caught: groovy.lang.MissingPropertyException: No such property: traceability for class: HelloWorld
groovy.lang.MissingPropertyException: No such property: traceability for class: HelloWorld
    at HelloWorld.testAddTraceEntry(HelloWorld.groovy:53)
    at HelloWorld.run(HelloWorld.groovy:57)

在功能testAddTraceEntry中,它显然不知道traceability的值,因此似乎为此提供了一个错误。

我试图返回traceability的值。

  def addTraceEntry(key, value) {
        def traceability = [:]
        traceability[key] = value.trim()
        println "This print happens in function addTraceEntry " + traceability
        return traceability
    }

但这会产生相同的错误。

2 个答案:

答案 0 :(得分:1)

看到您编写的代码后,还有很多事情值得一提。

第一件事-变量和封装的范围。让我们暂时抛弃技术性,集中精力做更重要的事情。在方法addTraceEntry中,您可以保留一些状态,这很好。但是,方法testAddTraceEntry的实现表明该方法试图对addTraceEntry的实现细节有很多了解。它封装(换句话说就是)持久性逻辑(从API的角度来看,作为调用者,您不知道它在映射内持久化了键和值),这就是testAddTraceEntry永远不应该这么做的原因假设调用此方法会改变某些结构。如果这样做,则:

  • 您的测试方法会产生副作用,而不是预期的业务逻辑(在某种全球地图中存储数据-永远不要这样做)
  • 您的测试阻止测试方法实现的任何发展-假设您决定将键和值存储在不同的结构中。您可以这样做而不会违反任何API约定(您的函数会产生相同的结果),但是测试方法将失败,您将不得不对其进行修改。

第二件事-您的addTraceEntry方法始终生成一个具有单个条目的地图。这没有多大意义,如果您调用函数,例如说4次,最终将得到4个映射,其中每个映射都包含一个映射到单个值的键。

至少有多种方法可以改善方法的实现。您可以做的最简单的事情是实现一个封装用于存储键和值的逻辑的类。考虑以下示例:

import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap

class TraceEntriesStorage {
  private final ConcurrentMap<String, Object> entries = [:] as ConcurrentHashMap

  def addTraceEntry(String key, Object value) {
    entries.put(key, value)
  }

  def containsTraceEntry(String key) {
    return entries.containsKey(key)
  }

  def retrieveTraceEntryForKey(String key) {
    return entries.get(key)
  }
}

这是带有3个简短方法的简单类。它将跟踪条目存储在内部并发映射内部(以解决并发访问问题)。现在,您的测试方法可能如下所示:

def storage = new TraceEntriesStorage()
storage.addTraceEntry("test_key", "test_value")

assert storage.containsTraceEntry("test_key")
assert storage.retrieveTraceEntryForKey("test_key") == "test_value"

您创建此类的实例,添加一个条目,并检查方法containsTraceEntryretrieveTraceEntryForKey是否返回期望值。如您所见,存储此跟踪条目的位置并不重要-我们实现的类的行为与预期一样重要。为了使此测试方法更好,您可以添加一个断言,以在我们实际插入test_key之前检查是否没有跟踪条目-这样,我们知道添加跟踪条目会更改类的内部状态。但是这种方法的好处是,只要我们不违约,就可以试验和修改TraceEntriesStorage的实现。因为最重要的是-添加跟踪条目必须允许从对象中取回它们。它的存储方式,存储位置-没关系。

希望此答案对您有所帮助,它将帮助您学习Groovy和设计更好的程序。祝您黑客愉快!

答案 1 :(得分:0)

您需要结合将return语句添加到addTraceEntry()和将返回值分配给testAddTraceEntry()中的变量:

def traceability = addTraceEntry(key, value)