Dale Highfill
Dale Highfill

Reputation: 123

How to add map entry outside of def

I'm writing groovy unit test and using Map coercion, I'm trying to figure out how to define a mock using a map, but then later in the test I want to add a method on the fly outside of the def statement. Is this possible?

Consider the following class.

class MapMockedClass{
   String aMethod() {
      return "original A method";
   }
   String bMethod( String str ) {
      return "original B method with parameter ${str}";
   }
}

I would like these tests to pass. See the test_Map_AddC, that's the one I can't figure out.

  void test_Map_Original() {
     def mock = new MapMockedClass()
     assertEquals( "original A method", mock.aMethod() );
     assertEquals( "original B method with parameter test", mock.bMethod("test") );
  }
  void test_Map_OverrideA() {
     def mock =  [ aMethod: "new A method" ] as MapMockedClass
     assertEquals( "new A method", mock.aMethod() );
     assertEquals( "original B method with parameter test", mock.bMethod("test") );
  }
  void test_Map_OverrideB() {
     def mock =  [ aMethod: "new A method",
                   bMethod: { param -> return "new B method with parameter ${param}" as String }] as MapMockedClass
     assertEquals( "new A method", mock.aMethod() );
     assertEquals( "new B method with parameter test", mock.bMethod("test") );
  }
  void test_Map_AddC() {
     def mock =  [ aMethod: "new A method",
        bMethod: { param -> return "new B method with parameter ${param}" as String }] as MapMockedClass
     assertEquals( "new A method", mock.aMethod() );
     assertEquals( "new B method with parameter test", mock.bMethod("test") );
     // Here I want to add a cMethod to the mock, but its not clear how to do it outside of the definition.
     //mock.inject( cMethod, { return "new C method" });
     //mock[ cMethod ] = { return "new C method" };
     //mock[ 'cMethod' ] = { return "new C method" };
     assertEquals( "new C method", mock.cMethod("test") );
 } 

Here are the new working methods after the answer was posted.

void test_Map_AddC() {
  def mock =  [ aMethod: "new A method",
        bMethod: { param -> return "new B method with parameter ${param}" as String }] as MapMockedClass
  assertEquals( "new A method", mock.aMethod() );
  assertEquals( "new B method with parameter test", mock.bMethod("test") );
  // Here I want to add a cMethod to the mock, but its not clear how to do it outside of the definition.
  mock.metaClass.cMethod = { return "new C method" };
  assertEquals( "new C method", mock.cMethod("test") );
}
void test_Map_ModifyAandB() {
  def mock =  [ aMethod: "new A method",
        bMethod: { param -> return "new B method with parameter ${param}" as String }] as MapMockedClass
  assertEquals( "new B method with parameter test", mock.bMethod("test") );

  // http://otherthanthink.blogspot.com/2012/08/how-to-override-groovy-instance-and.html
  mock.metaClass.aMethod = { return "An override for method a" }
  assertEquals( "An override for method a", mock.aMethod() );

  // Make sure you declare the String here otherwise it can't find the method.
  mock.metaClass.bMethod = { String param -> return "second B method with parameter ${param}" as String  };
  assertEquals( "second B method with parameter foo", mock.bMethod("foo") );
}

Upvotes: 0

Views: 49

Answers (1)

dmahapatro
dmahapatro

Reputation: 50285

cMethod has to be added to the metaClass of MapMockedClass.

mock.metaClass.cMethod = { String arg -> return "new C method" } 

Above line should be used before the assertion.

Upvotes: 2

Related Questions