The test platform series (84) supports copying other preconditions

Posted by quintin on Mon, 29 Nov 2021 22:44:49 +0100

Hello ~ I'm Milo!

I'm building an open source interface testing platform from 0 to 1, and I'm also writing a complete set of corresponding tutorials. I hope you can support me.

Welcome to my official account test development pit, get the latest article tutorial!

review

Previously, we supported the precondition of Redis, but in fact, there is a particularly unfriendly place:

If the preconditions are close, I can't even copy them.

If you can select one to copy quickly like the pre case, it is very unfriendly.

Let's realize it in this section.

design sketch

As the old rule, put the renderings first:

thinking

In fact, it is relatively simple for the backend to support this operation.

Fortunately, our backend Constructor has a type field to distinguish the types of preconditions. Therefore, we only need to arrange a query interface:

Find out the details of preconditions according to the type, and then select them. The front end will bring them in by form to copy the whole preconditions.

Back end first

Write the query interface, show which case it belongs to, and give the details of the preconditions.

The front end has been determined TreeSelect Component, so the back-end adopts two-tier data format:

[
  {
  "title": "Use case",
  "key": "caseid",
  "children": [
    {
      "title": "Data Constructor  A",
      "key":
      "constructor_id"
    }
  ]}
]

Let's build it~

  • Writing ideas

    I don't intend to use join (I have implemented my idea from the beginning. I prefer to use the method of twice querying and splicing data by myself. In fact, join is not used well)

    We first find out the preconditions of the corresponding type, and then we can get all cases_ ID, and then use case_ Isn't it beautiful to find out the case information?

    The difficulty lies in how to form the tree, but in fact, the tree has only two layers. What we have to do is to assemble children first and then spell parent.

    Here we will use defaultdict.

    1. Find out the preconditions that meet the conditions, and according to the case_ The method with ID as key and precondition as value is stored in defaultdict
    2. Find out the case according to the keys of defaultdict_ The case name corresponding to ID, traverse it, piece up the parent, and put the value in defaultdict into the children field.

    Let's look at the code:

    @staticmethod
    async def get_case_and_constructor(constructor_type: int):
        # Final return result tree
        ans = list()
        async with async_session() as session:
            # Store case here_ Id = > mapping of preconditions
            constructors = defaultdict(list)
            # Find out all preconditions according to the type of preconditions passed in. The types are the same. The sharing switch is turned on and has not been deleted
            query = await session.execute(
                select(Constructor).where(
                    Constructor.type == constructor_type,
                    Constructor.public == True,
                    Constructor.deleted_at == None))
            # And put these preconditions into constructors
            for q in query.scalars().all():
                constructors[q.case_id].append({
                    "title": q.name,
                    "key": f"{q.id}",
                    "isLeaf": True,
                    # This is to get the specific code, because the tree generally only has name and id, and we need other data
                    "constructor_json": q.constructor_json,
                })

            # Second query to find out the case s with preconditions
            query = await session.execute(
                select(TestCase).where(TestCase.id.in_(constructors.keys()), TestCase.deleted_at == None))
            # To construct the tree, you should know that the children have been built, which is in the constructors
            for q in query.scalars().all():
                # Put the Case id into cs_list, there is no need for native join here
                ans.append({
                    "title": q.name,
                    "key": f"case_{q.id}",
                    "disabled": True,
                    "children": constructors[q.id]
                })
        return ans

The notes were written in great detail and explained every step very clearly.

Then comes the interface part. There is no need to say more:

# Get all data constructors
@router.get("/constructor/list")
async def list_case_and_constructor(constructor_type: int):
    try:
        ans = await ConstructorDao.get_case_and_constructor(constructor_type)
        return PityResponse.success(ans)
    except Exception as e:
        return PityResponse.failed(str(e))

Front end adaptation

In fact, the front-end adaptation is very simple. Add a component and update the value of the form when the component selects the value.

oh shit~~

After writing here, I found that I had written similar code. It's hard ==

Sure enough, people will fall in the same place, but I think what I wrote before does not classify the preconditions, so I have to modify it, or use it as a v2 interface this time.

It has to be said that the change of the front end is a little bigger than expected. After carefully comparing this interface, it is found that its logic is:

  1. Find the corresponding precondition id
  2. Query the data of preconditions and replace them

However, the previous interface was only for case type, so it was very weak.

At present, we have made a new version of the ship, which is suitable for all our types:

import {Col, Row, TreeSelect} from "antd";
import {connect} from 'umi';
import {useEffect} from "react";

const CopyTreeSelect = ({construct, dispatch}) => {

  const {constructorData, searchConstructor, constructorType} = construct;


  const save = (data) => {
    dispatch({
      type: 'construct/save',
      payload: data,
    })
  }

  const getConstructorData = () => {
    dispatch({
      type: 'construct/getConstructorTree',
      payload: {
        constructor_type: constructorType
      }
    })
  }

  useEffect(() => {
    getConstructorData();
  }, [constructorType])

  return (
    <Row style={{marginTop: 24, marginBottom: 24}}>
      <Col span={3}/>
      <Col span={18}>
        <Row>
          <Col span={4}/>
          <Col span={20}>
            <TreeSelect
              allowClear
              showSearch
              style={{width: '100%'}}
              value={searchConstructor}
              filterTreeNode={(inputValue, treeNode) => {
                return treeNode.title.toLowerCase().indexOf(inputValue.toLowerCase()) > -1
              }}
              dropdownStyle={{maxHeight: 600, overflow: 'auto'}}
              treeData={constructorData}
              placeholder="You can quickly copy parameters by searching construction conditions!"
              treeDefaultExpandAll
              onChange={(e) => {
                save({searchConstructor: e})
                if (e !== undefined) {
                  dispatch({
                    type: 'construct/getConstructorData',
                    payload: {id: e.split("_")[1]}
                  })
                } else {
                  dispatch({
                    type: 'construct/save',
                    payload: {testCaseConstructorData: {type: constructorType, public: true, enable: true}},
                  })
                }
              }}
            />
          </Col>
        </Row>

      </Col>
      <Col span={3}/>
    </Row>

  )
}

export default connect(({loading, construct}) => ({loading, construct}))(CopyTreeSelect);

Extract this component separately to become a copy component. And automatically change the data source when the precondition type changes.

Make some fine-tuning on the page, and it's ok. To tell you the truth, this piece is a little bloated. Because I can't see it myself, I'll let go of myself and everyone first.

In the next section, we try to write a simple test report email notification function. (in fact, it's not easy to say. If you want to design a style, it's very troublesome)

Topics: Python React Testing FastAPI