首页 > 其他分享 >软件测试经理工作日常随记【7】-接口+UI自动化(多端集成测试)

软件测试经理工作日常随记【7】-接口+UI自动化(多端集成测试)

时间:2024-08-01 15:59:19浏览次数:20  
标签:get self driver element UI import 随记 def 软件测试

软件测试经理工作日常随记【7】-UI自动化(多端集成测试)

自动化测试前篇在此

前言

今天开这篇的契机是,最近刚好是运维开发频繁更新证书的,每次更新都在0点,每次一更新都要走一次冒烟流程。为了不让我的美容觉被阉割!(bushi)为了方便同事儿,不用每次更新都求爷告奶地通知大家辛苦半夜走一遍测试。我紧赶慢赶,于是有了此。因为此次冒烟涉及三个端,其中两个端采用接口自动化,另外一个端采用UI自动化,集成运行。

正文

工具类

用于UI自动化的工具类
# utils.py 用于UI自动化的工具类,包含在pc端有界面的执行和linux服务器无界面的执行(本段代码以linux服务器无界面运行为例)
"""
设置驱动
驱动停止
获取弹窗信息
获取data数据
"""
import json
import time

import allure
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from log.log import Logger


class UtilsDriver:

    @classmethod
    def get_driver(cls):
        """
        :return:浏览器驱动
        """
        if cls._driver is None:
            # 创建一个ChromeOptions对象
            chrome_options = Options()  # (linux服务运行1)
            # 添加--headless参数来启用无头模式
            chrome_options.add_argument("--headless")  # (linux服务运行2)
            # 指定ChromeDriver的路径(如果不在PATH环境变量中)
            # driver_path = '/path/to/chromedriver'
            # driver = webdriver.Chrome(executable_path=driver_path, options=chrome_options)
            # 如果ChromeDriver已经在PATH中,或者你可以直接调用它,则可以省略executable_path
            cls._driver = webdriver.Chrome(options=chrome_options)  # (linux服务运行3)

            # cls._driver = webdriver.Chrome()  # 谷歌(如在pc电脑有UI界面则不执行以上服务器执行的步骤,执行该行代码)

            cls._driver.maximize_window()
            cls._driver.implicitly_wait(5)
            cls._driver.get("http://********") 

            time.sleep(1)
        return cls._driver

    @classmethod
	"""
	关闭浏览器驱动
	"""
    def quit_driver(cls):
        if cls._driver is not None:
            cls.get_driver().quit()
            cls._driver = None

    @classmethod
	"""
	获取元素信息:用于断言
	"""
    def get_mes(cls, xpath):
        return UtilsDriver.get_driver().find_element(By.XPATH, xpath).text

    @classmethod
    def get_mes_wait(cls, xpath):
	"""
	显性等待获取元素信息
	"""
        wait = WebDriverWait(UtilsDriver.get_driver(), 10, 1)
        element = wait.until(lambda x: x.find_element(By.XPATH, xpath))
        return element

    @classmethod
    def get_mes_s(cls, xpath):
        """
        :param xpath: 元素的路径
        :return: 返回的是以元素列表,不可以直接取text,只能用for循环历遍各个元素并读取文本值
        """

        eles = UtilsDriver.get_driver().find_elements(By.XPATH, xpath)
        alist = []
        for ele in eles:
            ele_mes = ele.text
            alist.append(ele_mes)
        print(alist)
        return alist

    @classmethod
	"""
	显性等待获取元素定位
	"""
    def get_element_utils_wait(cls, location):  # page页对象层的基类,显式等待
        wait = WebDriverWait(UtilsDriver.get_driver(), 10, 1)
        element_wait = wait.until(lambda x: x.find_element(By.XPATH, location))
        return element_wait

    @classmethod
    def get_elements(cls, xpath):
        """
        :param xpath: 表示元素定位的路径
        :return: 返回找到的元素
        """
        return UtilsDriver.get_driver().find_elements(By.XPATH, xpath)

    @classmethod
    def get_attribute(cls, xpath, attribute):
        """
        以元素的属性值来断言,断言前必须延迟2s
        :param xpath: 找到元素的路径,只取到前面的标签,然后根据标签中的元素名来判断属性值对不对
        :param attribute: 标签中的元素名
        :return: 属性值
        """
        return UtilsDriver.get_driver().find_element(By.XPATH, xpath).get_attribute(attribute)

    @classmethod
    def get_text(cls, xpath, expected_msg, xpath2, expected_msg2):
        """
		有两个断言元素
        获取元素的文本来断言,断言前必须延迟2s
        :param xpath: 定位元素的路径1
        :param expected_msg: 断言参数1
        :param xpath2: 定位元素的路径2
        :param expected_msg2: 断言参数2
        """

        actual_mes = UtilsDriver.get_driver().find_element(By.XPATH, xpath).text
        actual_mes2 = UtilsDriver.get_driver().find_element(By.XPATH, xpath2).text
        print("生成截图")
        allure.attach(UtilsDriver.get_driver().get_screenshot_as_png(), "截图",
                      allure.attachment_type.PNG)
        print("第一个断言的实际mes:" + actual_mes + "第一个断言的预期结果" + expected_msg)
        Logger.logger_in().info("第一个断言的实际mes:" + actual_mes + ";第一个断言的预期结果" + expected_msg)
        print("第二个断言的实际mes:" + actual_mes2 + "第二个断言的预期结果:" + expected_msg2)
        Logger.logger_in().info("第二个断言的实际mes:" + actual_mes2 + ";第二个断言的预期结果:" + expected_msg2)
        assert expected_msg in actual_mes
        print("1断言成功!")
        Logger.logger_in().info('1断言成功!')
        assert expected_msg2 in actual_mes2
        print("2断言成功!")
        Logger.logger_in().info('2断言成功!')

    @classmethod
    def get_text_1(cls, xpath, expected_msg):
        """
		有一个断言元素
        获取元素的文本来断言,断言前必须延迟2s
        :param xpath:找到元素的路径,只取到前面的标签,然后根据标签中的元素名来判断属性值对不对
        :param expected_msg:期待定位的元素获取的值
        """
        actual_mes = UtilsDriver.get_driver().find_element(By.XPATH, xpath).text
        # actual_mes2 = UtilsDriver.get_driver().find_element(By.XPATH, xpath2).text
        print("生成截图")
        allure.attach(UtilsDriver.get_driver().get_screenshot_as_png(), "截图",
                      allure.attachment_type.PNG)
        print("实际mes:" + actual_mes + "预期结果" + expected_msg)
        Logger.logger_in().info("实际mes:" + actual_mes + ";预期结果" + expected_msg)
        assert expected_msg in actual_mes
        print("1断言成功!")
        Logger.logger_in().info('1断言成功!')

   
用于接口自动化的工具类
# utils_api.py,用于接口自动化的工具类
"""
设置驱动
驱动停止
获取弹窗信息
获取data数据
"""
import datetime
import requests
from log.log import Logger


class RequestUtils:
    session = requests.session()
  
    @classmethod
	"""
	定义发送请求的方法,参数为data
	"""
    def send_request_data(cls, url, method, data, **kwargs):
        try:
            Logger.logger_in().info('-----------------{}接口开始执行-----------------'.format(url))
            response = RequestUtils.session.request(url=url, method=method, data=data, **kwargs)
            Logger.logger_in().info('接口请求成功,响应值为:{}'.format(response.text))
            return response
        except Exception as e:
            Logger.logger_in().error('接口请求失败,原因为:{}'.format(repr(e)))
            return e

    @classmethod
	"""
	定义发送请求的方法,参数为json
	"""
    def send_request_json(cls, url, method, data, **kwargs):
        try:
            Logger.logger_in().info('-----------------{}接口开始执行-----------------'.format(url))
            print('-----------------{}接口开始执行-----------------'.format(url))
            response = RequestUtils.session.request(url=url, method=method, json=data, **kwargs)
            Logger.logger_in().info('接口请求成功,响应值为:{}'.format(response.text))
            Logger.logger_in().info('请求体为:{}'.format(response.request.body))
            print('请求体为:{}'.format(response.request.body))
            print('接口请求成功,响应值为:{}'.format(response.text))
            return response
        except Exception as e:
            Logger.logger_in().error('接口请求失败,原因为:{}'.format(repr(e)))
            return e

    @classmethod
	"""
	定义发送请求的方法(get请求,参数为拼接方式),参数为dicts(dicts = {'a': 1, 'b': 2, 'c': 3})
	"""
    def send_request_splicing(cls, dicts, url):  # 对应请求的入参及请求的函数
        Logger.logger_in().info('-----------------{}接口开始执行-----------------'.format(url))
        print('-----------------{}接口开始执行-----------------'.format(url))
        def parse_url(data: dict): # 将一个字典(data)转换成一个 URL 查询字符串(query string)
            item = data.items()
            urls = "?"
            for i in item:
                (key, value) = i
                temp_str = key + "=" + value
                urls = urls + temp_str + "&"
            urls = urls[:len(urls) - 1]
            print('请求体为:{}'.format(urls))
            Logger.logger_in().info('请求体为:{}'.format(urls))
            return urls
        response = RequestUtils.session.get(url + parse_url(dicts))
        Logger.logger_in().info('接口请求成功,响应值为:{}'.format(response.json()))
        print('接口请求成功,响应值为:{}'.format(response.json()))
        print(response.json()["data"][0]["a"]) #json串被解析为一个字典,data对应的值是一个列表,列表包含字典,取data列表的第一个字典中a键对应的值
        return response

base类

用于ui自动化定位元素继承使用

# base_ui.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from utils_app import UtilsDriver


class BaseApp:

    def __init__(self):
        print("引用基类:BaseApp")

        self.driver = UtilsDriver.get_app_driver()  # get_driver方法的引用就有隐形等待
        # self.driver.implicitly_wait(10)
        print("已获取app驱动")

    def get_element(self, location):  # page页对象层的基类,显式等待
        wait = WebDriverWait(self.driver, 10, 1)
        element = wait.until(lambda x: x.find_element(location))
        return element

    def get_elements(self, xpath):
        """
        :param xpath: 表示元素定位的路径
        :return: 返回找到的元素
        """
        wait = WebDriverWait(self.driver, 10, 1)
        element = wait.until(lambda x: x.find_element(By.XPATH, xpath))
        return element

    def get_element_id(self, ID):
        """
        :param ID:
        :return:
        """
        wait = WebDriverWait(self.driver, 15, 1)
        element = wait.until(lambda x: x.find_element(By.ID, ID))
        return element

    def get_element_text(self, XPATH):
        wait = WebDriverWait(self.driver, 15, 1)
        element = wait.until(lambda x: x.find_element(By.XPATH, XPATH))
        return element

    def get_app_element(self, location):
        wait = WebDriverWait(self.driver, 15, 1)
        element = wait.until(lambda x: x.find_element(*location))
        return element

    def get_element_wait(self, location):
        # page页对象层的基类,显式等待
        # (定义等待条件,当条件发生时才执行后续代码。程序会轮询查看条件是否发生(默认 10 秒),
        # 如果条件成立则执行下一步,否则继续等待,直到超过设置的最长时间,程序抛出异常。)
        # 相较于隐性等待,这个显性等待要明确等待条件和等待上限。比如隐性等待,只要元素存在,可找到就可以,但显性等待,我要明确条件是我的元素可见。而元素存在,并不一定是元素可见。
        # 显性等待的场景:操作引起了页面的变化,而接下来要操作变化的元素的时候,就需要使用显性等待
        wait = WebDriverWait(self.driver, 10, 1)
        element_wait = wait.until(lambda x: x.find_element(By.XPATH, location))
        return element_wait

    def get_switch_to_frame(self, ida):
        self.driver.implicitly_wait(10)
        ele_frame = self.driver.find_element(By.ID, ida)
        return self.driver.switch_to.frame(ele_frame)

    def get_element_1(self, xpath):
        """
        :param xpath: 表示元素定位的路径
        :return: 返回找到的元素
        """
        self.driver.implicitly_wait(10)
        return self.driver.find_element(By.XPATH, xpath)


class BaseHandle:

    def input_text(self, element, text):
        """
        :param element: 表示元素得对象
        :param text: 表示要输入的内容
        :return:
        """
        element.clear()
        element.send_keys(text)

log类

用于记录所有执行目录

# log.py
import logging
import datetime
import os


class Logger:
    __logger = None

    @classmethod
    def logger_in(cls):
        if cls.__logger is None:
            # 创建日志器
            cls.__logger = logging.getLogger("APIlogger")
            cls.__logger.setLevel(logging.DEBUG)
        # 判断是否存在handler,不然每次都会新建一个handler,导致日志重复输出
        if not cls.__logger.handlers:
            # 获取当前日期为文件名,年份最后2位+月份+日期
            file_name = str(datetime.datetime.now().strftime('%g' + '%m' + "%d")) + '.log'
            # 创建处理器
            handler = logging.FileHandler(os.path.join('', file_name))
            # handler = logging.StreamHandler()
            # 创建格式器
            formatter = logging.Formatter('%(asctime)s [%(filename)s:%(lineno)d] %(levelname)s  %(message)s',
                                          '%Y-%m-%d %H:%M:%S')
            cls.__logger.addHandler(handler)
            handler.setFormatter(formatter)
        return cls.__logger

page类

用于定位UI元素

形成业务用例的执行流程(以登录为例)

# page_ui.py
import time

import allure

from utils import UtilsDriver
from base.base_page import BasePage
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from log.log import Logger


class PageLogin(BasePage):  # 对象库层
    def __init__(self):
        super().__init__()

    def find_username(self):
        return self.get_element_1("//*/input[@placeholder='用户名']")

    def find_password(self):
        return self.get_element_1("//*/input[@placeholder='密码']")

    def find_login_bt(self):
        return self.get_element_1("(//div[contains(text(),'登录')])")


class HandleLogin: # 操作层
    def __init__(self):
        self.driver = UtilsDriver.get_driver()
        self.login_page = PageLogin()
        self.keys = Keys()
        self.ac = ActionChains(self.driver)

    def click_and_input_find_username(self, username):  # 点击用户名输入框
        self.login_page.find_username().click()
        for i in range(10):
            self.login_page.find_username().send_keys(Keys.BACK_SPACE)  # 无法使用clear,只能点10次BACK_SPACE
        self.login_page.find_username().send_keys(username)

    def click_and_input_find_password(self, password):
        self.login_page.find_password().click()
        for i in range(20):
            self.login_page.find_password().send_keys(Keys.BACK_SPACE)  # 无法使用clear,只能点10次BACK_SPACE
        self.login_page.find_password().send_keys(password)

    def click_login_bt(self):
        self.login_page.find_login_bt().click()


class LoginProxy: # 业务层

    def __init__(self):
        self.handle_login = HandleLogin()

    def login(self, username, password, xpath, expected_msg, xpath2, expected_msg2):
        time.sleep(1)
        self.handle_login.click_and_input_find_username(username)
        print("输入用户名")
        Logger.logger_in().info('输入用户名!')
        self.handle_login.click_and_input_find_password(password)
        print("输入密码")
        Logger.logger_in().info('输入密码!')
        self.handle_login.click_login_bt()
        print("点击登录")
        Logger.logger_in().info('点击登录!')
        time.sleep(2)
        UtilsDriver.get_text(xpath, expected_msg, xpath2, expected_msg2)

用于封装请求+断言的方法

会引用到utils_api.py中的方法

# page_api.py
class PageUrl:

    def __init__(self):
        self.session = requests.session()

    def post(self, url, method, data, assert_msg):
        response = RequestUtils().send_request_json(url, method, data)
        print("实际response:" + response.text + ";预期响应:" + assert_msg)
        assert response.text in assert_msg
        return response

    def get(self, url, params, assert_msg):  # 对应请求的断言的函数
        response = RequestUtils().send_request_splicing(url, params)
        print("实际response:" + str(response.json()) + ";预期响应:" + assert_msg)
        print("实际response.json()[‘data’][0][‘a’]:" + response.json()["data"][0]["a"])
        assert response.json()["data"][0]["a"] == assert_msg
        return response

test文件

接口自动化脚本的入口

# test_api.py
import os
import allure
import time
import sys
import pytest
import hashlib
import urllib.parse
# from page.page_login import LoginProxy
from page_url.page_url import PageUrl
from utils_app import DbMysql
from utils_url_def import RequestUtils  # 有导入就有可能执行
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)


class TestUrl:

    def setup_class(self):  # 实例化page中的业务对象
        """
        pytest中的测试类必须以“Test”开头,且不能有init方法
        你试下把"Login_test"更改以“Test”开头的命名
        如果还不行的话文件名更改成“test_”开头或者以“_test”结尾

        因为pytest命名规范有3点:
        文件名以“test_”开头或者以“_test”结尾
        测试类必须以“Test”开头,且不能有init方法
        测试方法必须以test开头
        """
        self.page_url = PageUrl()
        self.absolute_xpath = os.path.abspath(os.path.dirname(os.getcwd()))
        print("当前文件路径:"+BASE_DIR)  # 输入当前的文件路径

    @pytest.mark.run(order=1)# 执行顺序,数字越小越先执行
    @allure.title("用例名")  # 命名用例名称方式1
    @allure.severity(allure.severity_level.CRITICAL)# 关键用例
    @pytest.mark.skipif(condition=True, reason="暂停")  # 跳过
    @pytest.mark.parametrize("参数名1,参数名2,参数名3,参数名4,参数名5,参数名6",
                             [(f'{RequestUtils.参数A1}', f'{RequestUtils.参数B1}', 1,  '', '断言1'), 
                              (f'{RequestUtils.参数A2}', f'{RequestUtils.参数B2}', 1,  '', '断言2'),
                              ]) # 参数化,可用于执行多条用例; ''表参数为空
    def test_001_entrance(self, A, B, C, D, E, assert_msg):
        data = {
            "a": 1,
            "b": 2}
        self.page_url.patrol_add_new_001("http:***", "post", data, assert_msg)  
        time.sleep(2)

    @pytest.mark.run(order=2) # 执行顺序,数字越小越先执行
    @allure.title("用例名2")  # 命名用例名称方式1
    @allure.severity(allure.severity_level.NORMAL)# 正常级别用例
    # @pytest.mark.skipif(condition=True, reason="暂停")  # 暂停%s,%RequestUtils.test_number
    def test_003_wechat_api(self):
        dicts = {'a': 1, 'b': 2}
        url = "http:***"
        time.sleep(2)
        self.page_url.wechat_public_account_api(dicts, url, RequestUtils.test_number2)
        time.sleep(0.3)

UI自动化脚本的入口

# test_ui.py
"""
以模块名称作为测试套件的名称,不要全部堆在一个测试套件里
[pytest]#标识当前配置文件是pytest的配置文件
addopts=-s -v #标识pytest执行的参数
testpaths=./scripts #匹配搜索的目录
python_files=test_*.py #匹配搜索的文件
python_classes=Test* #匹配搜索的类
python_functions=test_* #匹配测试的方法

执行结果生成测试报告步骤
1先生成json数据---pytest 测试文件(在pytest.ini在addopts参数后+--alluredir report2)
2再把生成的json生成测试报告---allure generate report/ -o report/html --clean
allure generate report2/ -o report2/html --clean
注意目录的路径及名称
"""
import os
import allure
import time
import datetime
import sys
import pytest
from page.page_login import LoginProxy
from page_url.page_url import PageUrl
from page.page_inside_the_road_in_backstage import InsideTheRoadProxy
from page.page_finance_in_backstage import FinanceProxy
from utils import UtilsDriver
from utils_url_def import RequestUtils
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)


class TestLogin:
    def setup_class(self):  # 实例化page中的业务对象
        """
        pytest中的测试类必须以“Test”开头,且不能有init方法
        你试下把"Login_test"更改以“Test”开头的命名
        如果还不行的话文件名更改成“test_”开头或者以“_test”结尾

        因为pytest命名规范有3点:
        文件名以“test_”开头或者以“_test”结尾
        测试类必须以“Test”开头,且不能有init方法
        测试方法必须以test开头
        """
        self.driver = UtilsDriver.get_driver()
        self.driver.implicitly_wait(6)
        self.login_proxy = LoginProxy()
        self.inside_the_road_proxy = InsideTheRoadProxy()
        self.finance_proxy = FinanceProxy()
        self.page_url = PageUrl()
        self.current_time = str(datetime.datetime.now().strftime("%Y-%m-%d"))
        self.absolute_xpath = os.path.abspath(os.path.dirname(os.getcwd()))
        print("当前文件路径:"+BASE_DIR)  # 输入当前的文件路径
        print(self.current_time)

    def teardown_class(self):
        time.sleep(3)
        UtilsDriver.get_driver().quit()

    @allure.step(title="正向登录")
    @allure.title("用例名字")
    @allure.severity(allure.severity_level.BLOCKER)# 冒烟测试用例
    @pytest.mark.run(order=4)
    # @pytest.mark.skipif(condition=True, reason="暂停")  # 跳过该用例
    def test_001_login(self):
        self.login_proxy.login(
                               UtilsDriver.user,
                               UtilsDriver.pwd,
                               UtilsDriver.login_actual_xpath,
                               UtilsDriver.login_expected_mes,
                               UtilsDriver.login_actual_xpath,
                               UtilsDriver.login_expected_mes)#在UtilsDriver的方法中订单变量login_expected_mes

main文件

# main.py
import os
import pytest
if __name__ == '__main__':
    pytest.main()  # 这里已经执行了pytest.ini成为临时文件了(pytest的配置文件自己根据需求配置)
    os.system("allure generate report/ -o report/html --clean")  # 再次生成测试报告

依赖库

# requirements.txt
allure_python_commons==2.13.5
Appium_Python_Client==2.11.0
Appium_Python_Client==4.0.1
PyMySQL==1.1.0
pytest==8.1.1
Requests==2.32.3
selenium==4.23.1

后言

以上为多端集成联动测试的完全代码,也包含UI自动化和接口自动化的结合,用的是pytest框架,执行后自动生成allure测试报告。

标签:get,self,driver,element,UI,import,随记,def,软件测试
From: https://blog.csdn.net/nacy112/article/details/140827172

相关文章

  • 用于从连接到 LAN 交换机的四个 Arduino 扩展板读取/保存数据的 Python 代码
    我有四个Arduino扩展板连接到LAN交换机。每个人都会发出一条“HelloJane”消息。LAN交换机已连接到我的PC。我需要将每个Arduino的数据/消息保存在PC上的单独文件夹中。请帮助使用Python脚本/代码。我能够看到来自所有四个Arduino的消息,但无法将它们保存到文......
  • QT之ui控件随窗口布局的大小而自适应大小
    QT之ui窗口自适应布局新建个工程说明,注意此处勾上Generateform根据开发电脑的系统选择套件点开widget.ui,如图鼠标随意托几个常用控件展示,如图三个控件,如图,水平布局sizePolicy策略:图中,控件的sizePolicy策略将决定上面这三个控件组在自适应成的控件组的分配策略。Fi......
  • android.uid.system sendBroadcast失效的问题
    如果是系统应用android:sharedUserId="android.uid.system"报这个错 Callingamethodinthesystemprocesswithoutaqualifieduser:android.app.ContextImpl.sendBroadcast:1188android.content.ContextWrapper.sendBroadcast:解决添加如下权限<uses-permissionandroi......
  • 题解:CF559B Equivalent Strings
    CF559BEquivalentStrings题解题目描述吐槽一下,题目翻译有歧义。思路分析你会发现,当你需要判断字符串\(a,b\)是否等价时,如果长度为偶数,需要继续判断字符串\(a\)拆分的字串。所用知识s.substr(i,j)//在字符串s中,从位置i开始截取长度为j的字串参考代码#include<bits......
  • 【FANUC】发那科机器人ROBOGUIDE安装教程(含安装包)
    ......
  • Ant design pro和umi ui
    #Antdesignpro#在Antdesignpro中umi@4是不支持umiui可视化辅助编程工具(右下角的小球球),umi@3才支持umiui可视化辅助编程工具。在Antdesignpro官网默认使用的是umi@4,想要使用umi@3需要先卸载当前安装的pro-cli,卸载命令如下:npmuninstall-g@ant-design/pro-cli然后......
  • 劝你先别更新!!最新Stable Diffusion WebUI 1.10已来!WebUI终于支持SD3大模型了!你跑起来
    你的SD3大模型在SDWebUI1.10.0中跑起来了么?今天发现StableDiffusionWebUI于昨日推出了最新SDWebUI1.10.0版本。令人比较兴奋的是该版本支持了SD3大模型,同时也新增了DDIMCFG++采样器。主要更新内容如下:最新版本地址:更新后重启,可在WebUI设置中开启对T5文本的支持,......
  • ComfyUI PVC 手办工作流!一键生成你的专属卡通形象!
    前言ComfyUIPVC手办工作流!一键生成你的专属卡通形象!......
  • 1、.Net UI框架:UWP - .Net宣传系列文章
    UWP(UniversalWindowsPlatform)是微软推出的一种应用程序开发平台,它允许开发者创建能够在各种Windows10设备上运行的应用程序,包括PC、平板、手机、Xbox、HoloLens等。UWP是Windows10操作系统的核心组件之一,它提供了统一的API和开发工具,使得开发者能够编写一次代码,然后在多个......
  • services.tty、services.build 和 services.port 必须是映射
    我开始使用Docker和Python,并按照我购买的教科书进行操作。我遇到了这个错误,但我认为我的缩进是正确的。其他问题的答案都是关于缩进的,我可以在其他问题中看到缩进错误,但是是的,我认为我的答案是对的,所以我不确定我还做错了什么。version:'3.8'services:build:.......