Der Zweck dieses Artikels ist eine Notiz aus meiner Forschung zu jmockit 1.48.
Dokument http://jmockit.github.io/index.html
Quellcode https://github.com/jmockit/jmockit1
JavaDoc https://repo1.maven.org/maven2/org/jmockit/jmockit/1.48/jmockit-1.48-javadoc.jar
** Überprüfungsumgebung ** java version "1.8.0_202" Eclipse IDE for Enterprise Java Developers. Version: 2019-03 (4.11.0) Build id: 20190314-1200 JUnit4
Bei der Durchführung von Komponententests mit xUnit können die abhängigen Teile ein Problem darstellen und schwer zu testen sein.
Zum Beispiel in den folgenden Fällen. -Wenn es aufgrund abhängiger Teile schwierig ist, beliebigen Inhalt an das Testziel zurückzugeben
In diesen Fällen können Sie das Testen von Einheiten vereinfachen, indem Sie die von jmockit erstellten Methoden anstelle der abhängigen Teile verwenden.
Mit jmockit ist es möglich, anstelle des abhängigen Teils einen zum Testen geeigneten Wert an das Testziel zu übergeben und aufzuzeichnen und zu überprüfen, wie der abhängige Teil vom Testziel aufgerufen wurde. Ich werde.
(1) Laden Sie Jar aus dem Folgenden herunter und beziehen Sie sich auf das Projekt. https://mvnrepository.com/artifact/org.jmockit/jmockit
Oder fügen Sie für Maven Folgendes zu pom.xml hinzu
<!-- https://mvnrepository.com/artifact/org.jmockit/jmockit -->
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.48</version>
<scope>test</scope>
</dependency>
(2) Fügen Sie einen JUnit-Testfall hinzu
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import mockit.Mock;
import mockit.MockUp;
public class SimpleTest {
@Test
public void test() {
new MockUp<java.lang.Math>() {
@Mock
public double random() {
//Immer 2.Zufällige Rückgabe 5()Methode
return 2.5;
}
};
assertEquals(2.5, Math.random(), 0.1);
assertEquals(2.5, Math.random(), 0.1);
}
}
(3) Fügen Sie in der Ausführungskonfiguration zum Zeitpunkt der Junit-Ausführung "-javaagent: jmockit-1.48.jar" zum VM-Argument hinzu und führen Sie es aus.
Einzelheiten dazu finden Sie weiter unten: http://jmockit.github.io/tutorial/Introduction.html#runningTests
** Veranstaltung **
** Fehlerverfolgung **
java.lang.Exception: Method testVerifications should have no parameters
at org.junit.runners.model.FrameworkMethod.validatePublicVoidNoArg(FrameworkMethod.java:76)
at org.junit.runners.ParentRunner.validatePublicVoidNoArgMethods(ParentRunner.java:155)
//Abkürzung
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
** Ursache ** "-Javaagent: jmockit-1.48.jar" wird dem VM-Argument nicht hinzugefügt.
Gelegentlich gibt es eine Anweisung, dass es wichtig ist, den Build-Klassenpfad in der Reihenfolge jmockit → junit auszuführen. https://stackoverflow.com/questions/32817982/jmockit-wasnt-properly-initialized?rq=1
Wahrscheinlich ist dies in der aktuellen Version kein Problem, oder weil "-javaagent: jmockit-X.XX.jar" nicht zum VM-Argument hinzugefügt wurde.
Es scheint auch eine Möglichkeit zu geben, "@ RunWith (JMockit.class)" als eine andere Lösung für die Reihenfolge des Build-Klassenpfads zu verwenden, aber mindestens ab 1.48 ist dieses Attribut nicht vorhanden.
https://github.com/jmockit/jmockit1/issues/554
Mocking Das Verspotten bietet einen Mechanismus, um die zu testende Klasse von (einem Teil) ihren Abhängigkeiten zu trennen. Verwenden Sie die Annotationen @ Mocked / @ Injectable / @ Capturing, um eine verspottete Instanz zu erstellen. Die verspottete Instanz kann in Expectations (#expectations) auf das erwartete Verhalten eingestellt und in Verifications (#verifications) überprüft werden, wie die verspottete Instanz ausgeführt wurde.
Es ist möglich, die Annotation @Mocked als Parameter einer Testfallmethode oder als Feld einer Testfallklasse zu verspotten. Wenn Sie die Annotation @Mocked verwenden, werden alle Instanzen desselben Typs für die Dauer des Tests verspottet.
Jeder Typ kann verspottet werden, außer dem primitiven Typ und dem Array-Typ.
Betrachten wir nun, wie die folgende Klasse als Scheinobjekt verwendet wird.
** Testziel **
package SampleProject;
public class Hoge001 {
public int hoge(int x, int y) {
return x + y;
}
public String hoge(String x) {
return "test" + x;
}
}
** Beispiel für die Verwendung von Mocked **
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import SampleProject.Hoge001;
import mockit.Expectations;
import mockit.Mocked;
public class Test001 {
//Wenn Sie kein Modell verwenden...
@Test
public void test0() {
Hoge001 hoge = new Hoge001();
assertEquals(11, hoge.hoge(5,6));
assertEquals("testxxx", hoge.hoge("xxx"));
}
//Sie können eine verspottete Instanz erstellen, indem Sie sie als Parameter der Testmethode angeben
@Test
public void test1(@Mocked Hoge001 mock) {
new Expectations() {{
//hoge ist x=5, y =Wenn Sie mit 6 aufgerufen werden, geben Sie beim ersten Mal 99 zurück
mock.hoge(5,6);
result = 99;
}};
//Wenn Sie in Expectations ein Methodenergebnis angeben, wird dieser Wert abgerufen
assertEquals(99, mock.hoge(5,6));
//Standardwert, wenn Expectations kein Methodenergebnis angibt(null)Wird
assertEquals(null, mock.hoge("xxx"));
// @Wenn Sie Mocked verwenden, werden alle zutreffenden Instanzen für die Dauer des Tests verspottet.
Hoge001 hoge = new Hoge001();
assertEquals(99, hoge.hoge(5,6));
assertEquals(null, hoge.hoge("xxx"));
}
}
test0 () ist ein Testfall, wenn er nicht verspottet wird, und test1 () ist ein Testfall, bei dem @Mocked als Parameter verwendet wird. Während des Testfalls von test1 () sind alle Hoge001-Instanzen verspottete Instanzen.
Der folgende Test bestätigt, dass er verspottet wird, auch wenn Sie die Instanz nicht direkt im Testfall erstellt haben.
** Testziel ** Das Testziel ist Hoge002, das durch Erstellen einer Instanz von Hoge001 verwendet wird.
package SampleProject;
public class Hoge002 {
public int test(int x , int y) {
Hoge001 hoge1 = new Hoge001();
return hoge1.hoge(x*2, y*2);
}
}
** Testcode **
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import SampleProject.Hoge001;
import SampleProject.Hoge002;
import mockit.Expectations;
import mockit.Mocked;
public class Test001_3 {
//Sie können eine verspottete Instanz erstellen, indem Sie sie als Parameter der Testmethode angeben
@Test
public void test1(@Mocked Hoge001 mock) {
new Expectations() {{
//hoge ist x=10, y =Bei einem Aufruf von 12 wird beim ersten Mal 99 zurückgegeben
mock.hoge(10,12);
result = 99;
}};
Hoge002 hoge2 = new Hoge002();
assertEquals(99, hoge2.test(5,6));
}
}
Wenn Sie diesen Testfall ausführen, können Sie sehen, dass das von Hoge002 erstellte Hoge001 eine verspottete Version ist.
Wenn Sie @Mocked für ein Klassenfeld verwenden, verspotten alle Tests für die Klasse die Zielklasse.
** Testcode **
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import SampleProject.Hoge001;
import SampleProject.Hoge002;
import mockit.Expectations;
import mockit.Mocked;
public class Test001_2 {
//Verspottete Instanzen können in jedem Testfall verwendet werden, indem sie als Testklassenfelder angegeben werden.
@Mocked
private Hoge001 fieldMocked;
@Test
public void test1() {
new Expectations() {{
fieldMocked.hoge(anyInt, anyInt);
result = 100;
}};
assertEquals(100, fieldMocked.hoge(1,2));
}
@Test
public void test2() {
new Expectations() {{
//hoge ist x=10, y =Bei einem Aufruf von 12 wird beim ersten Mal 99 zurückgegeben
fieldMocked.hoge(10,12);
result = 99;
}};
Hoge002 hoge2 = new Hoge002();
assertEquals(99, hoge2.test(5,6));
}
}
Angenommen, Sie verfügen über Funktionen, die viele verschiedene Objekte verwenden. Aufrufe wie "obj1.getObj2 (...). GetYetAnotherObj (). DoSomething (...)" sind nicht ungewöhnlich. Schauen wir uns in diesem Fall ein Beispiel für ein Modell an.
Im folgenden Beispiel soll mit dem Code überprüft werden, ob in einer Methode, die ein Objekt wie mock.getDepend1 (). Output () zurückgibt, eine Verspottung durchgeführt wird.
** Klasse im Test **
package SampleProject;
public class Depend001 {
private String prefix;
public Depend001(String p) {
this.prefix = p;
}
public String output(String msg) {
return this.prefix + msg;
}
}
package SampleProject;
public class Hoge003 {
private Depend001 d1;
public Depend001 d2;
public Hoge003() {
}
public Hoge003(Depend001 depend1, Depend001 depend2) {
this.d1 = depend1;
this.d2 = depend2;
}
public String output() {
String ret = "";
ret = ret + this.d1.output("test1") + "\n";
ret = ret + this.d2.output("test2") + "\n";
return ret;
}
public Depend001 getDepend1() {
return this.d1;
}
}
** Testcode **
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import SampleProject.Hoge003;
import mockit.Expectations;
import mockit.Mocked;
public class Test002 {
@Test
public void test1(@Mocked Hoge003 mock) {
new Expectations() {{
mock.getDepend1().output(anyString);
result = "abcde";
}};
assertEquals("abcde", mock.getDepend1().output("abc"));
}
}
Es wurde bestätigt, dass das erwartete Verhalten der Zielmethode geändert werden kann, indem die ursprüngliche Hoge003-Klasse verspottet wird, ohne Depend001 der Zweige und Blätter wie im obigen Beispiel explizit zu verspotten.
Wie die Annotation @Mocked ist es eine Annotation zum Verspotten, aber der Unterschied zur Annotation @Mocked besteht darin, dass die Verspottung auf eine Instanz beschränkt ist. Es kann auch zur automatischen Injektion in das zu testende Objekt in Kombination mit der Annotation @Tested verwendet werden.
Um den Unterschied zwischen den Annotationen @Mocked und @Injectable zu erkennen, ändern Sie den in der Annotation @Mocked verwendeten Testcode in @Injectable und überprüfen Sie.
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import SampleProject.Hoge001;
import mockit.Expectations;
import mockit.Injectable;
public class Test004 {
//Sie können eine verspottete Instanz erstellen, indem Sie sie als Parameter der Testmethode angeben
@Test
public void test1(@Injectable Hoge001 mock) {
new Expectations() {{
//hoge ist x=5, y =Wenn Sie mit 6 aufgerufen werden, geben Sie beim ersten Mal 99 zurück
mock.hoge(5,6);
result = 99;
}};
//Wenn Sie in Expectations ein Methodenergebnis angeben, wird dieser Wert abgerufen
assertEquals(99, mock.hoge(5,6));
//Standardwert, wenn Expectations kein Methodenergebnis angibt(null)Wird
assertEquals(null, mock.hoge("xxx"));
// @Nicht alle anwendbaren Instanzen werden verspottet, wie dies bei Mocked der Fall ist.
Hoge001 hoge = new Hoge001();
assertEquals(11, hoge.hoge(5,6));
assertEquals("testxxx", hoge.hoge("xxx"));
}
}
Bei Verwendung der Annotation @Mocked wurde sie jedes Mal verspottet, wenn während des Testzeitraums eine Instanz der Zielklasse erstellt wurde. Bei Verwendung von @Injectable ist die Anzahl der verspotteten Instanzen jedoch auf eins begrenzt. Sie können sehen, dass Sie es tun.
Lassen Sie uns das Beispiel überprüfen, das ein Mock in das zu testende Objekt einfügt, das durch die Annotation @Tested angegeben wird. Es gibt zwei Methoden: Die eine besteht darin, in das Argument des Konstruktors des zu testenden Objekts, das durch @Tested angegeben wird, und das andere in das zu testende Feld einzufügen.
** In Konstruktorargumente einfügen ** Das Folgende ist ein Beispiel für die Angabe von abhängige1 und abhängige2, die die Argumente des Konstruktors von Hoge003 sind (Depend001 abhängig1, Depend001 abhängig2).
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import SampleProject.Depend001;
import SampleProject.Hoge003;
import mockit.Expectations;
import mockit.Injectable;
import mockit.Tested;
public class Test003 {
@Tested
Hoge003 target;
@Injectable
Depend001 depend1;
@Injectable
Depend001 depend2;
@Test
public void test1() {
new Expectations() {{
depend1.output(anyString);
result = "abcde";
depend2.output(anyString);
result = "xxxxx";
}};
assertEquals("abcde\nxxxxx\n", target.output());
}
}
** Wie man ins Feld spritzt ** Unten finden Sie ein Beispiel zum Injizieren in die Felder d1 und d2 des Hoge003-Objekts.
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import SampleProject.Depend001;
import SampleProject.Hoge003;
import mockit.Expectations;
import mockit.Injectable;
import mockit.Tested;
public class Test003B {
@Tested
Hoge003 target;
@Injectable
Depend001 d1;
@Injectable
Depend001 d2;
@Test
public void test1() {
new Expectations() {{
d1.output(anyString);
result = "abcde";
d2.output(anyString);
result = "xxxxx";
}};
assertEquals("abcde\nxxxxx\n", target.output());
}
}
Mithilfe des Wertelements der Annotation @Injectable ist es möglich, in das Feld oder Konstrukt des zu testenden primitiven Typs zu injizieren, das durch die Annotation @Tested angegeben wird.
package jmockittest;
import org.junit.Test;
import SampleProject.Depend001;
import mockit.Injectable;
import mockit.Tested;
public class Test005 {
@Tested
Depend001 tested;
@Test
public void test1(@Injectable("abc") String p) {
//Geben Sie Folgendes aus
// abcaaa
System.out.println(tested.output("aaa"));
}
@Test
public void test2(@Injectable("abc") String prefix) {
//Geben Sie Folgendes aus
// abcbbb
System.out.println(tested.output("bbb"));
}
}
test1 wird injiziert, indem das Konstruktorargument p des zu testenden Objekts angegeben wird, und test2 wird injiziert, indem das Feldpräfix des zu testenden Objekts angegeben wird.
Art | Name | Optionale Elemente und Beschreibung | Spezifizierter Wert |
---|---|---|---|
boolean | availableDuringSetup | Die getestete Klasse ist die Test-Setup-Methode (d. H.@Vor oder@Gibt an, ob es instanziiert und initialisiert wird, bevor (die als BeforeMethod annotierte Methode) oder danach ausgeführt wird. | false |
boolean | fullyInitialized | Gibt an, dass jedem nicht endgültigen Feld eines getesteten Objekts, das zur Injektion berechtigt ist, ein Wert zugewiesen werden soll. Wenn Sie Spring verwenden, wird die Verwendung auf der nächsten Seite beschrieben. https://stackoverflow.com/questions/25856210/injecting-only-some-properties-mocking-others | false |
boolean | global | Erstellt eine einzelne benannte Instanz der zu testenden Klasse, um anzugeben, ob sie während des Testlaufs verwendet wird. | false |
String | value | Feld zu testen/Wenn der Parametertyp Zeichenfolge, Grundelement oder Wrapper-Typ, numerischer Typ oder Aufzählungstyp ist, geben Sie einen Literalwert an. | "" |
** Testcode zur Überprüfung von availableDuringSetup und global **
package jmockittest;
import org.junit.Before;
import org.junit.Test;
import SampleProject.Hoge001;
import mockit.Tested;
public class Test007 {
@Tested(availableDuringSetup=true, global=true)
Hoge001 tested;
@Before
public void before()
{
//Anders als null: Wenn availableDuringSetup false ist, ist es null.
System.out.println("before:" + tested);
}
@Test
public void test1() {
//Nicht null
System.out.println("test1:" + tested);
}
@Test
public void test2() {
//Es kann bestätigt werden, dass mit Ausnahme von null dasselbe Objekt wie test1 verwendet wird
System.out.println("test2:" + tested);
}
}
Sie können die Standardklasse oder -schnittstelle mithilfe der Annotation @Capturing verspotten. Das folgende Beispiel ist ein Beispiel, das eine verspottete Methode für eine Schnittstelle und nicht für eine einzelne Implementierungsklasse erstellt.
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import mockit.Capturing;
import mockit.Expectations;
public class Test006 {
public interface Service { int doSomething(); }
final class ServiceImpl implements Service { public int doSomething() { return 1; } }
public final class TestedUnit {
private final Service service1 = new ServiceImpl();
private final Service service2 = new Service() { public int doSomething() { return 2; } };
public int businessOperation() {
return service1.doSomething() + service2.doSomething();
}
}
//Erstellen Sie ein Modell für eine Schnittstelle oder Standardklasse
@Test
public void test1(@Capturing Service anyService) {
new Expectations() {{ anyService.doSomething(); returns(3, 4); }};
int result = new TestedUnit().businessOperation();
assertEquals(7, result);
}
}
Expectations Erwartungen legt das erwartete Verhalten für Scheinobjekte fest, die einem bestimmten Test zugeordnet sind.
Während Expectations können Sie angeben, welche Parameter für die Mock-Objektmethode angegeben und welcher Wert zurückgegeben werden soll. Im folgenden Beispiel wird beispielhaft festgelegt, welcher Wert zurückgegeben wird, wenn die Methoden "String hoge (String)" und "int hoge (int, int)" ausgeführt werden.
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import SampleProject.Hoge001;
import mockit.Delegate;
import mockit.Expectations;
import mockit.Mocked;
public class Test008 {
//Wenn Sie das Ergebnis der Methode in Expectations angeben, stellen Sie sicher, dass der Wert erhalten wird.
@Test
public void test1(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge("test");
result = "abcde";
mock.hoge(5,6);
result = 99;
result = 100;
result = 101;
}};
// mock.hoge("test")Holen Sie sich den erwarteten Wert bei der Ausführung
assertEquals("abcde", mock.hoge("test"));
// mock.hoge(5,6)Holen Sie sich den erwarteten Wert bei der Ausführung
//Holen Sie sich den ersten in Erwartungen festgelegten Wert
assertEquals(99, mock.hoge(5,6));
//Holen Sie sich den zweiten in Erwartungen festgelegten Wert
assertEquals(100, mock.hoge(5,6));
//Holen Sie sich den dritten in Erwartungen festgelegten Wert
assertEquals(101, mock.hoge(5,6));
//Rufen Sie den zuletzt in Erwartungen festgelegten Wert ab
assertEquals(101, mock.hoge(5,6));
//Rufen Sie den zuletzt in Erwartungen festgelegten Wert ab
assertEquals(101, mock.hoge(5,6));
//Wenn die Argumente unterschiedlich sind, ist dies der Anfangswert
assertEquals(0, mock.hoge(7,6));
}
}
Mehrere Ergebnisse können wie unten gezeigt in Retouren zusammengefasst werden.
new Expectations() {{
mock.hoge("test");
result = "abcde";
mock.hoge(5,6);
returns(99, 100, 101);
}};
Im vorherigen Beispiel wurde der Rückgabewert nur zurückgegeben, wenn der Wert eines bestimmten Arguments akzeptiert wurde. Der Wert des Arguments kann jedoch flexibel festgelegt werden, indem ~ oder ~ als Argument angegeben wird.
Erwartungen hat mehrere beliebige Felder, die einen beliebigen Zweck darstellen.
type | name |
---|---|
Object | any |
Boolean | anyBoolean |
Byte | anyByte |
Character | anyChar |
Double | anyDouble |
Float | anyFloat |
Integer | anyInt |
Long | anyLong |
Short | anyShort |
String | anyString |
Ein Beispiel für die Verwendung eines beliebigen Felds lautet wie folgt.
@Test
public void test1_1(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyString);
result = "abcde";
mock.hoge(anyInt, anyInt);
result = 99;
}};
// mock.hoge("test")Holen Sie sich den erwarteten Wert bei der Ausführung
assertEquals("abcde", mock.hoge("test"));
assertEquals("abcde", mock.hoge("hogehoget"));
// mock.hoge(5,6)Holen Sie sich den erwarteten Wert bei der Ausführung
assertEquals(99, mock.hoge(5,6));
assertEquals(99, mock.hoge(99,1234));
}
Sie können auch feste Argumentwerte mit beliebigen Argumentwerten kombinieren. Erstellen Sie im folgenden Beispiel eine Scheinmethode, die 10 für hoge (5,6) und andernfalls 99 zurückgibt.
@Test
public void test1_2(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(5,6);
result = 10;
mock.hoge(anyInt, anyInt);
result = 99;
}};
// mock.hoge(5,6)Holen Sie sich den erwarteten Wert bei der Ausführung
assertEquals(10, mock.hoge(5,6));
assertEquals(99, mock.hoge(99,1234));
}
Geben Sie beim Kombinieren mit dem Wert eines Arguments zuerst den festen Wert ein.
Mit der with ~ -Methode kann flexibel beurteilt werden, ob sie mit der in Expectations angegebenen Mock-Methode übereinstimmt oder nicht.
Methode | Erläuterung |
---|---|
with(Delegate<? super T> objectWithDelegateMethod) | Verwenden Sie die Delegate-Methode, um festzustellen, ob die Argumente übereinstimmen. Wenn der Rückgabewert der Delegate-Methode true ist, bedeutet dies eine Übereinstimmung. |
withEqual(T arg) | Überprüft, ob der angegebene Wert mit dem Argument übereinstimmt, wenn der Mock ausgeführt wird. Verwenden Sie diese Methode im Allgemeinen nicht, sondern die Methode zum Übergeben des Werts des gewünschten Arguments. |
withEqual(double value, double delta) | Es wird angenommen, dass die Übereinstimmung nahe an dem durch Delta angegebenen Wert liegt. |
withEqual(float value, double delta) | Es wird angenommen, dass die Übereinstimmung nahe an dem durch Delta angegebenen Wert liegt. |
withAny(T arg) | Erwägen Sie die Verwendung von anyBoolean, anyByte, anyChar, anyDouble, anyFloat, anyInt, anyLong, anyShort, anyString, any. |
withNotEqual(T arg) | Wenn der Wert nicht dem angegebenen Wert entspricht, wird davon ausgegangen, dass er übereinstimmt. |
withNotNull() | Wenn der angegebene Wert nicht NULL ist, wird davon ausgegangen, dass er übereinstimmt. |
withNull() | Wenn der angegebene Wert NULL ist, wird angenommen, dass er übereinstimmt |
withInstanceOf(Class |
Stellen Sie sicher, dass es sich um eine Instanz der angegebenen Klasse handelt. |
withInstanceLike(T object) | Stellen Sie sicher, dass es sich um eine Instanz derselben Klasse wie das angegebene Objekt handelt. withInstanceOf(object.getClass())Wird gleichbedeutend sein mit |
withSameInstance(T object) | Stellen Sie sicher, dass es sich genau um dieselbe Instanz handelt |
withPrefix(T text) | Wenn ein bestimmtes Zeichen enthalten ist, wird es als Übereinstimmung betrachtet |
withSubstring(T text) | Wenn der Anfang mit dem angegebenen Zeichen übereinstimmt, wird davon ausgegangen, dass er übereinstimmt. |
withSuffix(T text) | Wenn das Ende mit dem angegebenen Zeichen übereinstimmt, wird davon ausgegangen, dass es übereinstimmt. |
withMatch(T regex) | Sie können angeben, ob mit einem regulären Ausdruck übereinstimmen soll |
Mithilfe der Delegate-Methode mit with kann beurteilt werden, ob die Scheinargumente in der Methode übereinstimmen.
@Test
public void test1_4(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(with(new Delegate<Integer>() {
@Mock boolean validate(int value) {
return value >= 0;
}
}),anyInt);
result = 99;
}};
//Da x positiv ist, entspricht es dem im Modell festgelegten Wert
assertEquals(99, mock.hoge(1,2));
//Da x negativ ist, stimmt es nicht mit dem im Modell festgelegten Wert überein
assertEquals(0, mock.hoge(-1,2));
}
Grundsätzlich ist es besser, das Literal so zu verwenden, wie es ist, als es mit Equal zu verwenden. Wenn Sie jedoch Gleitkomma verwenden möchten, sollten Sie withEqual verwenden.
class testWithEqual {
int test1(double v) {
return 1000;
}
int test2(int v) {
return 2000;
}
}
@Test
public void test_withEqual1(@Mocked testWithEqual mock) {
new Expectations() {{
mock.test2(withEqual(100));
result = 99;
}};
//Passender Mock.test2(100)Gleich wie
assertEquals(99, mock.test2(100));
//Es passt nicht
assertEquals(0, mock.test2(101));
}
@Test
public void test_withEqual2(@Mocked testWithEqual mock) {
new Expectations() {{
mock.test1(withEqual(100, 1));
result = 99;
}};
//Spiel
assertEquals(99, mock.test1(100.0));
assertEquals(99, mock.test1(101.0));
assertEquals(99, mock.test1(99.0));
//Es passt nicht
assertEquals(0, mock.test1(101.1));
assertEquals(0, mock.test1(98.99));
}
Sie können withInstanceOf, withInstanceOf, withSameInstance verwenden, um festzustellen, ob es mit einer bestimmten Instanz übereinstimmt.
class classA {
}
class classB {
}
class classX {
public int method1(Object obj) {
return 999;
}
}
@Test
public void test_withInst1(@Mocked classX mock) {
new Expectations() {{
mock.method1(withInstanceOf(classA.class));
result = 99;
}};
//Spiel
{
classA obj = new classA();
assertEquals(99, mock.method1(obj));
}
//Es passt nicht
{
classB obj = new classB();
assertEquals(0, mock.method1(obj));
}
}
@Test
public void test_withInst2(@Mocked classX mock) {
new Expectations() {{
classA objA = new classA();
mock.method1(withInstanceLike(objA));
result = 99;
}};
//Spiel
{
classA obj = new classA();
assertEquals(99, mock.method1(obj));
}
//Es passt nicht
{
classB obj = new classB();
assertEquals(0, mock.method1(obj));
}
}
@Test
public void test_withInst3(@Mocked classX mock) {
classA obj1 = new classA();
new Expectations() {{
mock.method1(withSameInstance(obj1));
result = 99;
}};
//Spiel
{
assertEquals(99, mock.method1(obj1));
}
//Es passt nicht
{
classA obj2 = new classA();
assertEquals(0, mock.method1(obj2));
}
}
Mit withPrefix, withSubstring, withSuffix, withMatch kann überprüft werden, ob ein Teil der Zeichenfolge übereinstimmt.
@Test
public void test_withString1(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(withPrefix("abc"));
result = "test";
}};
//Das folgende Spiel
assertEquals("test", mock.hoge("abc"));
assertEquals("test", mock.hoge("abcAA"));
//Folgendes stimmt nicht überein
assertEquals(null, mock.hoge("AAabc"));
assertEquals(null, mock.hoge("AabcA"));
assertEquals(null, mock.hoge("xx"));
}
@Test
public void test_withString2(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(withSuffix("abc"));
result = "test";
}};
//Das folgende Spiel
assertEquals("test", mock.hoge("abc"));
assertEquals("test", mock.hoge("AAabc"));
//Folgendes stimmt nicht überein
assertEquals(null, mock.hoge("abcAA"));
assertEquals(null, mock.hoge("AabcA"));
assertEquals(null, mock.hoge("xx"));
}
@Test
public void test_withString3(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(withSubstring("abc"));
result = "test";
}};
//Das folgende Spiel
assertEquals("test", mock.hoge("abc"));
assertEquals("test", mock.hoge("abcAA"));
assertEquals("test", mock.hoge("AAabc"));
assertEquals("test", mock.hoge("AabcA"));
//Folgendes stimmt nicht überein
assertEquals(null, mock.hoge("xx"));
}
@Test
public void test_withString4(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(withMatch("[0-9]+"));
result = "test";
}};
//Das folgende Spiel
assertEquals("test", mock.hoge("1234"));
//Folgendes stimmt nicht überein
assertEquals(null, mock.hoge("xxx"));
}
Es ist möglich, die Mock-Methode danach zu unterteilen, wie die Instanz in Expectations erstellt wird. Das folgende Beispiel zeigt ein Beispiel, das die Mock-Methode nur auf die Instanz anwendet, die durch Ausführen von "new TestA (10)" erstellt wurde.
class TestA {
public TestA(int x) {
}
public int hoge() {
return 99999;
}
}
@Test
public void test8(@Mocked TestA mock) {
new Expectations() {{
TestA t1 = new TestA(10);
t1.hoge();
result = 10;
}};
{
TestA obj = new TestA(10);
assertEquals(10, obj.hoge());
}
{
TestA obj = new TestA(99);
assertEquals(0, obj.hoge());
}
}
Sie können eine Ausnahme auslösen, während Sie eine Scheinmethode verarbeiten. Im folgenden Beispiel wird beim Ausführen der hoge () -Methode eine IllegalArgumentException ausgelöst.
//Ein Beispiel für die Rückgabe einer Methodenausnahme in Expectations
@Test
public void test2(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(5,6);
result = 99;
result = new IllegalArgumentException("test");
}};
//Holen Sie sich den ersten in Erwartungen festgelegten Wert
assertEquals(99, mock.hoge(5,6));
try {
//Holen Sie sich den zweiten in Erwartungen festgelegten Wert
mock.hoge(5,6);
fail();
} catch (IllegalArgumentException ex) {
assertEquals("test", ex.getMessage());
}
}
Sie können angeben, wie oft eine Methode ausgeführt wird, indem Sie in Expectations times, maxTImes und minTimes angeben.
Field | Description |
---|---|
tiems | Gibt an, wie oft die Methode während der Ausführung aufgerufen wird. Wenn es anders oft aufgerufen wird, tritt ein Fehler auf. |
maxTimes | Gibt die maximale Anzahl der aufgerufenen Methoden an. Wenn es mehrmals aufgerufen wird, tritt ein Fehler auf. |
minTimes | Gibt die Mindestanzahl der aufzurufenden Methoden an. Ein Fehler tritt auf, wenn er weniger als so oft aufgerufen wird. |
@Test
public void test4_1(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
times = 3;
}};
assertEquals(99, mock.hoge(5,6));
assertEquals(99, mock.hoge(99,1234));
assertEquals(99, mock.hoge(3,6));
}
//Dieser Test schlägt mit fehlenden 2 Aufrufen fehl
@Test
public void test4_2(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
times = 3;
}};
assertEquals(99, mock.hoge(3,6));
}
//Dieser Test führt zu einem unerwarteten Aufruf und einem Fehler
@Test
public void test4_3(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
times = 3;
}};
assertEquals(99, mock.hoge(5,6));
assertEquals(99, mock.hoge(99,1234));
assertEquals(99, mock.hoge(3,6));
assertEquals(99, mock.hoge(3,6));
}
@Test
public void test5_1(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
minTimes = 3;
}};
assertEquals(99, mock.hoge(5,6));
assertEquals(99, mock.hoge(99,1234));
assertEquals(99, mock.hoge(3,6));
}
//Dieser Test schlägt mit fehlenden 2 Aufrufen fehl
@Test
public void test5_2(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
minTimes = 3;
}};
assertEquals(99, mock.hoge(3,6));
}
@Test
public void test5_3(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
minTimes = 3;
}};
assertEquals(99, mock.hoge(5,6));
assertEquals(99, mock.hoge(99,1234));
assertEquals(99, mock.hoge(3,6));
assertEquals(99, mock.hoge(3,6));
}
@Test
public void test6_1(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
maxTimes = 3;
}};
assertEquals(99, mock.hoge(5,6));
assertEquals(99, mock.hoge(99,1234));
assertEquals(99, mock.hoge(3,6));
}
@Test
public void test6_2(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
maxTimes = 3;
}};
assertEquals(99, mock.hoge(3,6));
}
//Dieser Test führt zu einem unerwarteten Aufruf und einem Fehler
@Test
public void test6_3(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt, anyInt);
result = 99;
maxTimes = 3;
}};
assertEquals(99, mock.hoge(5,6));
assertEquals(99, mock.hoge(99,1234));
assertEquals(99, mock.hoge(3,6));
assertEquals(99, mock.hoge(3,6));
}
Verwenden Sie Deglegate, wenn Sie das vom Mock zurückgegebene Ergebnis basierend auf den Argumenten bei der Ausführung der Mock-Methode ändern möchten. Im folgenden Beispiel wird eine Scheinmethode erstellt, die einen Wert zurückgibt, der doppelt so hoch ist wie das Eingabeargument.
@Test
public void test7(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt,anyInt);
result= new Delegate<Integer>() {
@SuppressWarnings("unused")
int aDelegateMethod(int x, int y) {
return x * 2 + y * 2;
}
};
}};
//Holen Sie sich den ersten in Erwartungen festgelegten Wert
assertEquals(22, mock.hoge(5,6));
}
Es ist möglich, Invocation als ersten Parameter der Delegate-Methode zu verwenden. Invocation bietet folgende Getter:
Methode | Erläuterung |
---|---|
getInvocationCount() | Anzahl der Anrufe |
getInvocationIndex() | Aktuellen Anrufindex abrufen |
getInvokedArguments() | Rufen Sie das für den Aufruf verwendete Argument ab |
getInvokedInstance() | Instanz des aktuellen Anrufs. Null für statische Methoden |
getInvokedMember() | Methode aufrufen/Konstruktor holen |
proceed(Object... replacementArguments) | Tatsächliche Methode/Führen Sie den Konstruktor aus |
@Test
public void testDelegate2(@Mocked Hoge001 mock) {
new Expectations() {{
mock.hoge(anyInt,anyInt);
result= new Delegate<Integer>() {
@SuppressWarnings("unused")
int aDelegateMethod(Invocation inv ,int x, int y) {
System.out.println("--------------------------------");
//Anzahl der Anrufe
System.out.format("Invocation getInvocationCount %d \n", inv.getInvocationCount());
//Index des aktuellen Anrufs
System.out.format("Invocation getInvocationIndex() %d \n", inv.getInvocationIndex());
//Holen Sie sich Argument
System.out.println("getInvokedArguments");
for(Object obj : inv.getInvokedArguments()) {
System.out.println(obj);
}
//Holen Sie sich eine Instanz
System.out.format("Invocation getInvokedInstance() %s \n", inv.getInvokedInstance().toString());
//Holen Sie sich die eigentliche Methode
System.out.format("Invocation getInvokedMember() %s \n", inv.getInvokedMember().toString());
//Die eigentliche Methode kann ausgeführt werden.
System.out.format("Invocation proceed %s \n", inv.proceed().toString());
//Die eigentliche Methode kann durch Manipulation des Arguments ausgeführt werden
System.out.format("Invocation proceed %s \n", inv.proceed(5,6).toString());
return 0;
}
};
}};
//Holen Sie sich den ersten in Erwartungen festgelegten Wert
Hoge001 a = new Hoge001();
Hoge001 b = new Hoge001();
a.hoge(5,6);
a.hoge(45,63);
b.hoge(99,100);
}
Das Konsolenprotokoll, das das oben genannte ausgeführt hat, lautet wie folgt.
--------------------------------
Invocation getInvocationCount 1
Invocation getInvocationIndex() 0
getInvokedArguments
5
6
Invocation getInvokedInstance() SampleProject.Hoge001@2a2d45ba
Invocation getInvokedMember() public int SampleProject.Hoge001.hoge(int,int)
Invocation proceed 11
Invocation proceed 11
--------------------------------
Invocation getInvocationCount 2
Invocation getInvocationIndex() 1
getInvokedArguments
45
63
Invocation getInvokedInstance() SampleProject.Hoge001@2a2d45ba
Invocation getInvokedMember() public int SampleProject.Hoge001.hoge(int,int)
Invocation proceed 108
Invocation proceed 11
--------------------------------
Invocation getInvocationCount 3
Invocation getInvocationIndex() 2
getInvokedArguments
99
100
Invocation getInvokedInstance() SampleProject.Hoge001@675d3402
Invocation getInvokedMember() public int SampleProject.Hoge001.hoge(int,int)
Invocation proceed 199
Invocation proceed 11
Um nur einige der Methoden statt aller zu verspotten, übergeben Sie das Objekt wie folgt an Expectations:
@Test
public void test10() {
Hoge001 hoge = new Hoge001();
new Expectations(hoge) {{
hoge.hoge(5,6);
result = 99;
}};
//Gibt das Ergebnis des Mocks zurück
assertEquals(99, hoge.hoge(5,6));
//Führen Sie die eigentliche Methode aus
assertEquals(3, hoge.hoge(1,2));
assertEquals("testabc", hoge.hoge("abc"));
}
Verifications Mit Verifications, VerificationsInOrder und FullVerifications können Sie explizit überprüfen, wie ein Scheinobjekt aufgerufen wurde.
@Test
public void test_v1(@Mocked Hoge001 mock) {
mock.hoge(1,2);
mock.hoge(2,3);
mock.hoge(4,5);
//
new Verifications() {{
mock.hoge(anyInt,anyInt);
times = 3;
mock.hoge(anyString);
times = 0;
}};
//Bei Überprüfungen werden nicht ordnungsgemäße oder zusätzliche Anrufe berücksichtigt
new Verifications() {{
mock.hoge(4,5);
mock.hoge(1,2);
}};
}
@Test
public void test_v2(@Mocked Hoge001 mock) {
mock.hoge(1,2);
mock.hoge(2,3);
mock.hoge(4,5);
//VerificationsInOrder führt zu einem Fehler, wenn die Reihenfolge anders ist
/*
new VerificationsInOrder() {{
mock.hoge(4,5);
mock.hoge(1,2);
}};
*/
new VerificationsInOrder() {{
mock.hoge(1,2);
mock.hoge(4,5);
}};
}
@Test
public void test_v3(@Mocked Hoge001 mock) {
mock.hoge(1,2);
mock.hoge(2,3);
mock.hoge(4,5);
//FullVerifications führt zu einem Fehler, wenn zusätzliche Anrufe getätigt werden
/*
new FullVerifications() {{
mock.hoge(1,2);
mock.hoge(4,5);
}};
*/
new FullVerifications() {{
mock.hoge(1,2);
mock.hoge(2,3);
mock.hoge(4,5);
}};
//Es wird auch dann bestehen, wenn die Reihenfolge anders ist
new FullVerifications() {{
mock.hoge(4,5);
mock.hoge(2,3);
mock.hoge(1,2);
}};
}
Mit Capture können Sie eine Instanz mit einem beliebigen Parameter in List abrufen.
//Beispiel für die Überprüfung von Parametern mit withCapture
@Test
public void test_v4(@Mocked Hoge001 mock) {
mock.hoge(1,2);
mock.hoge(2,3);
mock.hoge(4,5);
//
new Verifications() {{
List<Integer> argXList = new ArrayList<Integer>();
List<Integer> argYList = new ArrayList<Integer>();
mock.hoge(withCapture(argXList),withCapture(argYList));
assertEquals(3, argXList.size());
assertEquals(3, argYList.size());
assertEquals(1, (int)argXList.get(0));
assertEquals(2, (int)argXList.get(1));
assertEquals(4, (int)argXList.get(2));
assertEquals(2, (int)argYList.get(0));
assertEquals(3, (int)argYList.get(1));
assertEquals(5, (int)argYList.get(2));
}};
}
//Beispiel für die Bestätigung der Instanzerstellung mit withCapture
class Person {
public Person(String name , int age) {
}
}
@Test
public void test_v5(@Mocked Person mockPerson) {
new Person("Joe", 10);
new Person("Sara", 15);
new Person("Jack", 99);
//
new Verifications() {{
List<Person> created = withCapture(new Person(anyString, anyInt));
assertEquals(3, created.size());
}};
}
Faking API Die Faking-API bietet Unterstützung beim Erstellen von Fake-Implementierungen. Fake zielt normalerweise auf einige der Methoden und Konstruktoren in der Klasse Fake ab, und die meisten anderen Methoden und Konstruktoren bleiben unverändert.
Im folgenden Beispiel ist nur Proc1 der Klasse, in der Proc1 und Proc2 existieren, Fake.
package jmockittest;
import static org.junit.Assert.*;
import org.junit.Test;
import mockit.Mock;
import mockit.MockUp;
public class FakeTest {
class ClassA {
protected String Proc1() {
return "...Proc1";
}
public String Proc2() {
return "Proc2:" + this.Proc1();
}
}
@Test
public void test1() {
new MockUp<ClassA>() {
@Mock
String Proc1() {
System.out.print("Proc1");
return "xxx";
}
};
ClassA obj = new ClassA();
assertEquals("Proc2:xxx", obj.Proc2());
}
}
Mit 1.48 nicht möglich. Ich erhalte folgende Fehlermeldung:
java.lang.IllegalArgumentException: Unsupported fake for private method ClassA#Proc1()Ljava/lang/String; found
at jmockittest.FakeTest$1.<init>(FakeTest.java:22)
at jmockittest.FakeTest.test1(FakeTest.java:22)
Wahrscheinlich scheint es, dass es vorher gemacht wurde und nicht gemacht werden kann. https://github.com/jmockit/jmockit1/issues/605
Eine Fälschung der statischen Methode ist möglich. Das folgende Beispiel ist ein Beispiel für java.lang.Math.random, das immer einen festen Wert zurückgibt.
@Test
public void test() {
new MockUp<java.lang.Math>() {
@Mock
public double random() {
//Immer 2.Zufällige Rückgabe 5()Methode
return 2.5;
}
};
assertEquals(2.5, Math.random(), 0.1);
assertEquals(2.5, Math.random(), 0.1);
}
Es war möglich zu erstellen.
class ClassB {
final protected String Proc1() {
return "...Proc1";
}
public String Proc2() {
return "Proc2:" + this.Proc1();
}
}
@Test
public void test3() {
new MockUp<ClassB>() {
@Mock
String Proc1() {
System.out.print("Proc1");
return "xxx";
}
};
ClassB obj = new ClassB();
assertEquals("Proc2:xxx", obj.Proc2());
}
Es gibt \ $ init, \ $ Klinik, \ $ Ratschläge als spezielle Methoden in der Fake-Klasse. \ $ init zielt auf den Konstruktor ab. Die Klinik ist für statische Initialisierer vorgesehen. \ $ Advice repräsentiert alle Methoden der Zielklasse.
** Testziel **
ClassC.java
package SampleProject;
public class ClassC {
public static int sx;
private int x;
static {
sx = 999;
}
public ClassC(int x) {
this.x = x;
}
public String Proc1() {
System.out.format("ClassC Proc1 %d %d\n", sx, this.x);
return "...Proc1";
}
}
** Testcode **
@Test
public void test4() {
new MockUp<ClassC>() {
@Mock
void $clinit() {
//Stellen Sie sicher, dass die statische Initialisierung von ClassiC nicht funktioniert
assertEquals(0, ClassC.sx);
}
@Mock
void $init(int x) {
assertEquals(100, x);
}
@Mock
Object $advice(Invocation inv) {
return "test";
}
};
ClassC obj = new ClassC(100);
assertEquals("test", obj.Proc1());
}
Es ist möglich, [Invocation](mit #invocation) als ersten Parameter der Fake-Methode zu verwenden. Unten sehen Sie ein Beispiel, das dies verwendet, um einen festen Wert für die aktuelle Zeit zurückzugeben.
@Test
public void testTime() {
Calendar nowCalendar = Calendar.getInstance();
System.out.println("Aktuelles Datum und Uhrzeit: " + nowCalendar.getTime());
new MockUp<Calendar>() {
@Mock
Calendar getInstance(Invocation inv) {
Calendar cal = inv.proceed();
cal.set(Calendar.YEAR, 2018);
cal.set(Calendar.MONTH, 0);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR, 22);
cal.set(Calendar.MINUTE, 32);
cal.set(Calendar.SECOND, 12);
cal.set(Calendar.MILLISECOND, 512);
return cal;
}
@Mock
Calendar getInstance(Invocation inv, TimeZone zone, Locale aLocale) {
Calendar cal = inv.proceed();
cal.set(Calendar.YEAR, 2018);
cal.set(Calendar.MONTH, 0);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR, 22);
cal.set(Calendar.MINUTE, 32);
cal.set(Calendar.SECOND, 12);
cal.set(Calendar.MILLISECOND, 512);
return cal;
}
};
final Calendar c = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
assertEquals("20180102103212512", sdf.format(c.getTime()));
}
Die Ergebnisse der Abdeckungsmessung können ausgegeben werden, indem VM-Argumente in der Ausführungskonfiguration angegeben werden.
-Dcoverage-output=html -Dcoverage-srcDirs=..\SampleProject\src
Weitere Argumente finden Sie weiter unten. http://jmockit.github.io/tutorial/CodeCoverage.html
Als undokumentiertes Verhalten scheint "-Dcoverage-output = xml" XML auszugeben.
Ich habe bisher recherchiert, aber angesichts der Diskussion um die private Methode auf GitHub und des Abbruchverlaufs des Update-Verlaufs halte ich die Verwendung für etwas riskant, wenn Sie sich nicht in einer vollständigen und perfekten idealen Testumgebung befinden. ..
Außerdem habe ich unten Powermock + Mockito überprüft.
** Versuchen Sie es mit powermock-mockito2-2.0.2 ** https://qiita.com/mima_ita/items/3574a03b3379fb5f3c3c
Recommended Posts