2010-05-25 4 views
0

Je construis un test dans lequel je dois envoyer une question et attendre la réponse. Le passage de message n'est pas le problème. En fait, pour savoir quelle réponse correspond à quelle question, j'utilise un identifiant. Mon identifiant est généré à l'aide d'un UUID. Je veux récupérer cet identifiant, qui est donné en paramètre à un objet mocké. Il ressemble à ceci:Utilisation de jmock comment réutiliser le paramètre

oneOf(message).setJMSCorrelationID(with(correlationId)); 
      inSequence(sequence); 

Où correlationId est la chaîne que je voudrais garder pour une autre expecteation comme celui-ci:

oneOf(session).createBrowser(with(inputChannel), 
      with("JMSType ='pong' AND JMSCorrelationId = '"+correlationId+"'")); 

Avez-vous une réponse?

+0

Votre test génère-t-il l'ID? Ou le code sous test le génère-t-il? Les deux attentes se produisent-elles dans le même cas de test? –

+0

le code en cours de test et générer ce oui enfin avec l'exemple ci-dessous, utiliser deux fois, et finnaly comparer l'argument passé, il a travaillé – benzen

Répondre

0

Une autre option à considérer, où l'ID de corrélation ne vient? Est-ce que cette activité doit être injectée pour que vous puissiez la contrôler et la vérifier dans le test?

+0

je travaille sur un vieux programme j2se donc je ne peux pas utiliser l'injection de dépendance Je pourrais utiliser l'injection manuelle, mais cela va paraître bizarre. Mais en général, vous id est bon – benzen

4

Vous devez créer vos propres actions. Voici le mien:

/** 
* puts the parameter array as elements in the list 
* @param parameters A mutable list, will be cleared when the Action is invoked. 
*/ 
public static Action captureParameters(final List<Object> parameters) { 
    return new CustomAction("captures parameters") { 
     public Object invoke(Invocation invocation) throws Throwable { 
      parameters.clear(); 
      parameters.addAll(Arrays.asList(invocation.getParametersAsArray())); 
      return null; 
     } 
    }; 
} 

Vous utilisez ensuite comme ceci (avec une importation statique):

final List<Object> parameters = new ArrayList<Object>(); 
    final SomeInterface services = context.mock(SomeInterface.class); 
    context.checking(new Expectations() {{ 
     oneOf(services).createNew(with(6420), with(aNonNull(TransactionAttributes.class))); 
      will(doAll(captureParameters(parameters), returnValue(true))); 
    }}); 

Pour faire ce que vous voulez, vous devez implémenter votre propre matcher. Voilà ce que je piraté en (un peu nulle vérification à l'écart, et bien sûr j'utiliser simplement des interfaces bien connues pour l'échantillon):

@RunWith(JMock.class) 
public class Scrap { 

private Mockery context = new JUnit4Mockery(); 

@Test 
public void testCaptureParameters() throws Exception { 
    final CharSequence mock = context.mock(CharSequence.class); 
    final ResultSet rs = context.mock(ResultSet.class); 
    final List<Object> parameters = new ArrayList<Object>(); 
    context.checking(new Expectations(){{ 
     oneOf(mock).charAt(10); 
      will(doAll(JMockActions.captureParameters(parameters), returnValue((char) 0))); 
     oneOf(rs).getInt(with(new ParameterMatcher<Integer>(parameters, 0))); 
    }}); 

    mock.charAt(10); 
    rs.getInt(10); 
} 

private static class ParameterMatcher<T> extends BaseMatcher<T> { 
    private List<?> parameters; 
    private int index; 

    private ParameterMatcher(List<?> parameters, int index) { 
     this.parameters = parameters; 
     this.index = index; 
    } 

    public boolean matches(Object item) { 
     return item.equals(parameters.get(index)); 
    } 

    public void describeTo(Description description) { 
     description.appendValue(parameters.get(index)); 
    } 
} 
} 
+0

avec cette technique, il semble que je ne peux pas utiliser le contenu des paramètres immédiatement après , dans la même définition d'attente – benzen

+0

@BenZen, je n'ai jamais essayé, mais je ne peux pas imaginer pourquoi cela ne fonctionnerait pas. Je vais essayer. – Yishai

0

J'ai trouvé une autre solution sur ce site http://www.symphonious.net/2010/03/09/returning-parameters-in-jmock-2/

import org.hamcrest.*; 
import org.jmock.api.*; 

public class CapturingMatcher<T> extends BaseMatcher<T> implements Action { 
public T captured; 

public boolean matches(Object o) { 
    try { 
     captured = (T)o; 
     return true; 
    } catch (ClassCastException e) { 
     return false; 
    } 
} 

public void describeTo(Description description) { 
    description.appendText("captured value "); 
    description.appendValue(captured); 
} 

public Object invoke(Invocation invocation) throws Throwable { 
    return captured; 
} 
} 

Il peut alors être utilisé comme:

context.checking(new Expectations() {{ 
CapturingMatcher<String> returnCapturedValue = new CapturingMatcher<String>(); 
allowing(mockObject).getParameter(with(equal("expectedParameterName")), with(returnCapturedValue)); will(returnCapturedValue); 
}}); 
+0

Pas mal, bien que l'auteur ne comprenne pas le cast dans le contexte des génériques (le ClassCastException ne peut pas être lancé à cause de l'effacement du type sauf si T a été déclaré pour étendre quelque chose). L'inconvénient de cette solution est que vous ne capturez pas réellement le paramètre pour une utilisation ultérieure dans le test, si cela est important. – Yishai

+0

en fait cette solution aide seulement si vous utilisez immédiatement la valeur capturée votre solution est bonne je l'ai utilisé, désolé – benzen

+0

Il est préférable d'utiliser une action plutôt qu'un Matcher si vous avez besoin de capturer un paramètre. Les correspondants peuvent être appelés n'importe quel nombre de fois, alors qu'une action ne sera appelée qu'une seule fois pour l'invocation. –

Questions connexes