Ich möchte eine Map erstellen, die Strings als Schlüssel enthält und Instanzen der Klasse Candidate
als Werte spottet.JMockit kann nicht mehr als eine Instanz der Klasse vortäuschen
Map<String, Long> domainNameToId = new HashMap<String, Long>();
domainNameToId.put("farmaciapuentezurita.es", 1234l);
domainNameToId.put("vivefarma.com", 2345l);
domainNameToId.put("eurofarmacia.com", 3456l);
Map<String, Candidate> expectedCandidates = new HashMap<String, Candidate>();
for(String domain : domainNameToId.keySet()) {
final Candidate cand = new MockUp<Candidate>() {
@Mock Long getDomainId() { return domainNameToId.get(domain); } // private method
@Mock boolean validateAndPrepare() { return true; }
@Mock String getRepresentingName() { return domain; }
}.getMockInstance();
expectedCandidates.put(domain, cand);
}
Der obige Code verwendet zu arbeiten, bevor JMockit 1,20-1,28 aktualisieren.
Jetzt bekomme ich eine Ausnahme:
java.lang.IllegalStateException: Ungültige Versuch nicht initialisierte Instanz der Klasse com.urlservice.data.Candidate von staatenlos Mockup auf zu bekommen ...
ich die Dokumentation zu lesen und versuchte new MockUp(T targetInstance)
stattdessen in der folgenden Art und Weise zu verwenden (dies ist die körpereigene Schleife):
final Candidate cand = new Candidate(domain);
new MockUp<Candidate>(cand) {
@Mock Long getDomainId() { return domainNameToId.get(domain); } // private method
@Mock boolean validateAndPrepare() { return true; }
@Mock String getRepresentingName() { return domain; }
};
Das Ergebnis war sehr seltsam - der erste Kandidat wurde richtig verspottet, während der Rest der verhöhnten Kandidaten überhaupt nicht verspottet wurde und ihre wahren Methoden genannt wurden.
Ich habe versucht, zurück in die Expectations
API zurückzukehren:
final Candidate cand = new Candidate(domain);
new Expectations(cand) {{
cand.getDomainId(); result = domainNameToId.get(domain); // Had to make it public :-(
cand.validateAndPrepare(); result = true;
cand.getRepresentingName(); result = domain;
}};
ohne Erfolg:
java.lang.IllegalArgumentException: Klasse com.urlservice.data.Candidate bei: Bereits verspottet ...
Ich möchte wirklich auf die neueste Version aktualisieren, aber ich kann keine Problemumgehung für dieses Problem finden.
UPDATE: Ich habe es nicht geschafft, dieses Problem in irgendeiner Version bis zu 1.28 zu reproduzieren, also denke ich, das ist die Version, in der es eingeführt wurde.
Zusätzlich zu meinem zweiten Beispiel (new MockUp(T targetInstance)
), sah ich den Quellcode der Klasse MockUp
Linie 402 und es sieht für mich wie das erwartete Verhalten ist, keine spezifische Zielinstanz außer dem ersten zu verspotten:
MockUp<?> previousMockUp = findPreviouslyFakedClassIfMockUpAlreadyApplied();
if (previousMockUp != null) {
targetType = previousMockUp.targetType;
mockedClass = previousMockUp.mockedClass;
return; // Input param targetInstance is disregarded
}
Was fehlt mir?
UPDATE2: Ich kam mit einem fehlerhaften Testbeispiel. Es ist ein bisschen umständlich, aber ich bin sicher, dass es den Punkt durchkommen wird.
public class SampleTest {
class TestedClass {
private IncrementingDependency dep;
TestedClass(IncrementingDependency dep) { this.dep = dep; }
public int getVal() { return dep.inc(); }
}
class IncrementingDependency {
int val;
public IncrementingDependency(int val) { this.val = val; }
public int inc() { return ++val; }
}
@Test
public void sampleTest() {
List<Integer> inputVals = Arrays.asList(1, 2, 3);
List<TestedClass> incrementingClasses = new ArrayList<TestedClass>();
for (Integer num : inputVals) {
IncrementingDependency dep = new IncrementingDependency(num);
new MockUp<IncrementingDependency>(dep) {
@Mock int inc() { return num; } // Mock with different behavior - DON'T INCREMENT
};
incrementingClasses.add(new TestedClass(dep));
}
assertThat(incrementingClasses.get(0).getVal()).isEqualTo(1); // Passes - 1 wasn't incremented (mocked behavior)
assertThat(incrementingClasses.get(1).getVal()).isEqualTo(2); // Fails - real code was called and 2 was incremented to 3
assertThat(incrementingClasses.get(2).getVal()).isEqualTo(3); // We never get to this point
}
}
Bitte beachten Sie, dass selbst wenn dieses Beispiel nicht gescheitert wäre, die Tatsache, dass ich, bevor es zu MockUp
‚s Konstruktor meine Abhängigkeit instanziiert muß vorbei ist bestenfalls problematisch. Ist das nicht der Sinn eines Mocks, dass man es nicht instanziieren muss?
Ich konnte das "seltsame" Ergebnis nicht reproduzieren, wenn ich 'new MockUp (cand) 'verwende. Es scheint mit 1,28 gut zu funktionieren. Können Sie einen fehlerhaften Beispieltest zeigen? –
Beachten Sie die [API-Dokumentation] (http://jmockit.org/api1x/mockit/MockUp.html#MockUp-T-) für 'Mock (T)' sagt "betrifft nur die angegebene Instanz". So werden Methoden, die an irgendwelchen * anderen * Instanzen von 'Kandidat' aufgerufen werden, nicht zur '@ Mock'-Methode gehen. –
@ Rogério Genau das habe ich natürlich versucht. Ich werde versuchen, einen fehlerhaften Beispieltest so schnell wie möglich zur Verfügung zu stellen, aber stellt das JMockit-Codebeispiel, das ich am Ende gestellt habe, meinen Anspruch nicht stark zurück? – KidCrippler