【问题标题】:Error when attempting to POST JSON object in API test尝试在 API 测试中发布 JSON 对象时出错
【发布时间】:2023-03-27 15:12:01
【问题描述】:

我会非常具体地说明我在这里想要实现的目标。帮助将不胜感激。 我目前正在创建一个这样的测试 JSON 对象:

    String testTrainingRecord(int employeeId, String date, String courseTitle) {
    String zeroDate = date.substring(0, 11) + "00:00:00";
    return "{\"id\":0,\"employeeId\":" + employeeId + ",\"dateIdentified\":\"" + zeroDate + "\",\"dateFrom\":\"" + zeroDate + "\"," +
            "\"dateTo\":\"" + zeroDate + "\",\"courseTitle\":\"" + courseTitle + "\",\"courseProvider\":\"APIprovider\",\"category\":\"API\",\"subject\":\"Recruitment\"," +
            "\"location\":\"Bristol\",\"cost\":0,\"duration\":0,\"durationHours\":0,\"cpdhours\":0,\"cpdpoints\":0,\"evaluationCompleted\":true,\"nonAttendance\":true," +
            "\"notes\":\"APInote\",\"reviewDate\":\"" + zeroDate + "\",\"developmentStatus\":\"APIdevelopment\",\"priorityLevel\":\"Level1\"," +
            "\"lastUpdate\":\"" + zeroDate + "\"}";
}

然后我在测试中执行此操作,并将其发布到 API 并且工作正常:

.body(testTrainingRecord(employeeId, date, courseTitle)).log().all()

我想做的是这样的:

    public class testTrainingRecord2 {
    HashMap<String, String> hashMapString = new HashMap<String, String>();
    HashMap<String, Integer> hashMapInt = new HashMap<String, Integer>();
    HashMap<String, Boolean> hashMapIBool = new HashMap<String, Boolean>();

    public testTrainingRecord2(int employeeId, String date, String courseTitle) {
        String zeroDate = date.substring(0, 11) + "00:00:00";

        hashMapInt.put("id", 0);
        hashMapInt.put("employeeId", employeeId);
        hashMapString.put("dateIdentified", zeroDate);
        hashMapString.put("dateFrom", zeroDate);
        hashMapString.put("dateTo", zeroDate);
        hashMapString.put("courseTitle", courseTitle);
        hashMapString.put("courseProvider", "APIprovider");
        hashMapString.put("category", "API");
        hashMapString.put("subject", "Recruitment");
        hashMapString.put("location", "Bristol");
        hashMapInt.put("cost", 0);
        hashMapInt.put("duration", 0);
        hashMapInt.put("durationHours", 0);
        hashMapInt.put("cpdhours", 0);
        hashMapInt.put("cpdpoints", 0);
        hashMapIBool.put("evaluationCompleted", true);
        hashMapIBool.put("nonAttendance", true);
        hashMapString.put("notes", "APInote");
        hashMapString.put("reviewDate", zeroDate);
        hashMapString.put("developmentStatus", "APIdevelopment");
        hashMapString.put("priorityLevel", "Level1");
        hashMapString.put("lastUpdate", zeroDate);

        return;
    }
}

我试图这样发布:

.body(new testTrainingRecord2(employeeId, date, courseTitle)).log().all()

但是,当测试运行时,错误如下:

com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class TrainingTests$testTrainingRecord2 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )

at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:26)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:118)
at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:1819)
at com.fasterxml.jackson.databind.ObjectMapper$writeValue$0.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:135)
at io.restassured.internal.mapping.Jackson2Mapper.serialize(Jackson2Mapper.groovy:53)
at io.restassured.internal.mapping.Jackson2Mapper.serialize(Jackson2Mapper.groovy)
at io.restassured.mapper.ObjectMapper$serialize.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
at io.restassured.internal.mapping.ObjectMapping.serializeWithJackson2(ObjectMapping.groovy:196)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce.invoke(StaticMetaMethodSite.java:149)
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.callStatic(StaticMetaMethodSite.java:100)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:55)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:196)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:216)
at io.restassured.internal.mapping.ObjectMapping.serialize(ObjectMapping.groovy:141)
at io.restassured.internal.mapping.ObjectMapping$serialize.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
at io.restassured.internal.RequestSpecificationImpl.body(RequestSpecificationImpl.groovy:750)
at TrainingTests.testPostTrainingRecord(TrainingTests.java:105)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

有人愿意帮忙吗? :)

【问题讨论】:

  • jackson 抱怨testTrainingRecord2 没有任何公共可访问属性 (stackoverflow.com/questions/8367312/…),即使您为 hashmaps 提供 getter 和 setter,该对象也不会反映 json 在全部。您放入哈希图中的属性应该是类的公共字段。

标签: java json api rest-assured


【解决方案1】:

MarcoLucidi 已经指出了这一点,但更典型的方法是使用公共字段定义类,或者甚至可能是 properties,这将满足称为 encapsulation 的 OO 原则。 property 是一个私有字段,例如:

private int cost;

可以通过 gettersetter 方法访问,例如:

public int getCost() {
    return cost;
}

public void setCost(int cost) {
    this.cost = cost;
}

你的班级的结果是:

public class TestTrainingRecord2 {

    private boolean evaluationCompleted;
    private boolean nonAttendence;

    private int id;
    private int employeeId;
    private int cost;
    private int duration;
    private int durationHours;
    private int cpdhours;
    private int cpdpoints;

    private String dateIdentified;
    private String dateFrom;
    private String dateTo;
    private String courseTitle;
    private String courseProvider;
    private String category;
    private String subject;
    private String location;
    private String notes;
    private String reviewDate;
    private String developmentStatus;
    private String priorityLevel;
    private String lastUpdate;
    private String zeroDate;

    public TestTrainingRecord2(int employeeId, String date, String courseTitle) {

        this.zeroDate = date + "00:00:00";

        this.employeeId = employeeId;
        this.dateIdentified = date;
        this.dateFrom = zeroDate;
        this.dateTo = zeroDate;
        this.courseTitle = courseTitle;
        this.courseProvider = "APIprovider";
        this.category = "API";
        this.subject = "Recruitment";
        this.location = "Bristol";
        this.cost = 0;
        this.duration = 0;
        this.durationHours = 0;
        this.cpdhours = 0;
        this.cpdpoints = 0;
        this.evaluationCompleted = true;
        this.nonAttendence = true;
        this.notes = "APInote";
        this.reviewDate = zeroDate;
        this.developmentStatus = "APIdevelopment";
        this.priorityLevel = "Level1";
        this.lastUpdate = zeroDate;
    }

    public boolean isEvaluationCompleted() {
        return evaluationCompleted;
    }

    public void setEvaluationCompleted(boolean evaluationCompleted) {
        this.evaluationCompleted = evaluationCompleted;
    }

    public boolean isNonAttendence() {
        return nonAttendence;
    }

    public void setNonAttendence(boolean nonAttendence) {
        this.nonAttendence = nonAttendence;
    }

    public int getCost() {
        return cost;
    }

    public void setCost(int cost) {
        this.cost = cost;
    }

    // ... other getters and setters omitted, but I will include them if you prefer
}

IntelliJ 等许多开发环境实际上只需单击几下即可为您编写 getter 和 setter。

然后Jackson会毫无怨言地为你序列化对象。这是一个将您的对象视为 JSON 的快速测试:

TestTrainingRecord2 record = new TestTrainingRecord2(0, "someDate", "someCourse");

ObjectMapper mapper = new ObjectMapper(); // from com.fasterxml.jackson.databind.ObjectMapper

String jsonString = mapper.writeValueAsString(record);

System.out.println(jsonString);

结果:

{"evaluationCompleted":true,"nonAttendence":true,"id":0,"employeeId":0,"cost":0,"duration":0,"durationHours":0,"cpdhours":0,"cpdpoints":0,"dateIdentified":"someDate","dateFrom":"someDate00:00:00","dateTo":"someDate00:00:00","courseTitle":"someCourse","courseProvider":"APIprovider","category":"API","subject":"Recruitment","location":"Bristol","notes":"APInote","reviewDate":"someDate00:00:00","developmentStatus":"APIdevelopment","priorityLevel":"Level1","lastUpdate":"someDate00:00:00"}

【讨论】:

  • 完美。这正是我想做的。也很好解释。非常感谢您的帮助,我真的很感激。
【解决方案2】:

即使您在 TestTrainingRecord2.java 类中为 3 个 HashMap 属性设置了 getter、setter 和“公共”访问修饰符,我认为您预期的 json 也不会被创建。这将是一个具有三个属性(hashMapString、hashMapInt、hashMapIBool)的 Java 类,JSON 对象如下所示;

{
  "hashMapString" : {
    "key_1": "value_1",
    "key_2": "value_2",
    "key_3": "value_3"
  },
  "hashMapInt": {
    "key_1": 1,
    "key_2": 2,
    "key_3": 3"
  },
  "hashMapIBool": {
    "key_1": true,
    "key_2": true,
    "key_3": false
  }
}

因此,您要做的是创建一个 Java 类并将所有键、值对添加为属性及其值。并为他们提供公共访问修饰符。并为它们中的每一个创建 getter 和 setter;

public class TestTrainingRecord2 {

    public String string_1;
    public int int_1;
    public String bool_1;

    public String getString_1() {
        return string_1;
    }

    public void setString_1(String string_1) {
        this.string_1 = string_1;
    }

    public int getInt_1() {
        return int_1;
    }

    public void setInt_1(int int_1) {
        this.int_1 = int_1;
    }

    public String getBool_1() {
        return bool_1;
    }

    public void setBool_1(String bool_1) {
        this.bool_1 = bool_1;
    }
}

或者你可以创建一个HashMap,以String作为key数据类型,Object作为value数据类型;

    HashMap<String,Object> map = new HashMap<>();

    map.put("key_1", "value_1");
    map.put("key_2", 1);
    map.put("key_3", true);

并通过它;

.body(map).log().all()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    相关资源
    最近更新 更多