Test Design Considerations

本文介绍了使用Selenium进行自动化测试的设计考量,包括常见的测试类型如静态内容测试、链接测试及功能测试等,并探讨了动态元素定位策略及Ajax元素处理方法。此外,还介绍了测试设计模式,例如页面对象模式和数据驱动测试。

原文地址:SeleniumHQ-Docs-Test Design Considerations

Introducing Test Design

We’ve provided in this chapter information that will be useful to both those new to test automation and for the experienced QA professional. Here we describe the most common types of automated tests. We also describe ‘design patterns’ commonly used in test automation for improving the maintenance and extensibily of your automation suite. The more experienced reader will find these interesting if not already using these techniques.

Types of Tests

What parts of your application should you test? That depends on aspects of your project: user expectations, time allowed for the project, priorities set by the project manager and so on. Once the project boundaries are defined though, you, the tester, will certainly make many decisions on what to test.

We’ve created a few terms here for the purpose of categorizing the types of test you may perform on your web application. These terms are by no means standard, although the concepts we present here are typical for web-application testing.

Testing Static Content

The simplest type of test, a content test, is a simple test for the existence of a static, non-changing, UI element. For instance

  • Does each page have its expected page title? This can be used to verify your test found an expected page after following a link.
  • Does the application’s home page contain an image expected to be at the top of the page?
  • Does each page of the website contain a footer area with links to the company contact page, privacy policy, and trademarks information?
  • Does each page begin with heading text using the < h1/> tag? And, does each page have the correct text within that header?

You may or may not need content tests. If your page content is not likely to be affected then it may be more efficient to test page content manually. If, for example, your application involves files being moved to different locations, content tests may prove valuable.

A frequent source of errors for web-sites is broken links or missing pages behind links. Testing involves clicking each link and verifying the expected page. If static links are infrequently changed then manual testing may be sufficient. However if your web designers frequently alter links, or if files are occasionally relocated, link tests should be automated.

Function Tests

These would be tests of a specific function within your application, requiring some type of user input, and returning some type of results. Often a function test will involve multiple pages with a form-based input page containing a collection of input fields, Submit and Cancel operations, and one or more response pages. User input can be via text-input fields, check boxes, drop-down lists, or any other browser-supported input.

Function tests are often the most complex tests you’ll automate, but are usually the most important. Typical tests can be for login, registration to the site, user account operations, account settings changes, complex data retrieval operations, among others. Function tests typically mirror the user-scenarios used to specify the features and design or your application.

Testing Dynamic Elements

Often a web page element has a unique identifier used to uniquely locate that element within the page. Usually these are implemented using the html tag’s ‘id’ attribute or its ‘name’ attribute. These names can be a static, i.e unchanging, string constant. They can also be dynamically generated values that vary each instance of the page. For example, some web servers might name a displayed document doc3861 one instance of a page, and ‘doc6148’ on a different instance of the page depending on what ‘document’ the user was retrieving. A test script verifying that a document exists may not have a consistent identifier to use for locating that document. Often, dynamic elements with varying identifiers are on some type of result page based on a user action. This though certainly depends on the function of the web application.
Here’s an example.

<input type="checkbox" value="true" id="addForm:_ID74:_ID75:0:_ID79:0: checkBox"/>

This shows an HTML tag for a check box. Its ID (addForm:_ID74:_ID75:0:_ID79:0:checkBox) is a dynamically generated value. The next time the same page is opened it will likely be a different value.

Ajax Tests

Ajax is a technology which supports dynamically changing user interface elements which can dynamically change without the browser having to reload the page, such as animation, RSS feeds, and real-time data updates among others. There are countless ways Ajax can be used to update elements on a web page. But, the easy way to think of this is that in Ajax-driven applications, data can be retrieved from the application server and then displayed on the page without reloading the entire page. Only a portion of the page, or strictly the element itself is reloaded.

Validating Results

Assert vs. Verify

When should you use an assert command and when should you use a verify command? This is up to you. The difference is in what you want to happen when the check fails. Do you want your test to terminate, or to continue and simply record that the check failed?

Here’s the trade-off. If you use an assert, the test will stop at that point and not run any subsequent checks. Sometimes, perhaps often, that is what you want. If the test fails you will immediately know the test did not pass. Test engines such as TestNG and JUnit have plugins for commonly used development environments (Chap 5) which conveniently flag these tests as failed tests. The advantage: you have an immediate visual of whether the checks passed. The disadvantage: when a check does fail, there are other checks which were never performed, so you have no information on their status.

In contrast, verify commands will not terminate the test. If your test uses only verify commands you are guaranteed (assuming no unexpected exceptions) the test will run to completion whether the checks find defects or not. The disadvantage: you have to do more work to examine your test results. That is, you won’t get feedback from TestNG or JUnit. You will need to look at the results of a console printout or a log output. And you will need to take the time to look through this output every time you run your test. If you are running hundreds of tests, each with its own log, this will be time-consuming, and the immediate feedback of asserts will be more appropriate. Asserts are more commonly used than verifiers due to their immediate feedback.

Location Strategies

Choosing a Location Strategy

There are multiple ways of selecting an object on a page. But what are the trade offs of each of these locator types? Recall we can locate an object using

  • the element’s ID
  • the element’s name attribute
  • an XPath statement
  • by a link’s text
  • document object model (DOM)

Using an element ID or name locator is the most efficient in terms of test performance, and also makes your test code more readable, assuming the ID or name within the page source is well-named. XPath statements take longer to process since the browser must run its XPath processor. XPath has been known to be especially slow in Internet Explorer version 7. Locating via a link’s text is often convenient and performs well. This technique is specific to links though. Also, if the link’s text is likely to change frequently, locating by the

Locating Dynamic Elements

As was described earlier in the Types of Tests section, a dynamic element is a page element whose identifer varies with each instance of the page. For example,

<a class="button" id="adminHomeForm" onclick="return oamSubmitForm('adminHomeForm', 'adminHomeForm:_ID38');" href="#">View Archived Allocation Events</a>

This HTML anchor tag defines a button with an ID attribute of “adminHomeForm”. It’s a fairly complex anchor tag when compared to most HTML tags, but it is still a static tag. The HTML will be the same each time this page is loaded in the browser. Its ID remains constant with all instances of this page. That is, when this page is displayed, this UI element will always have this Identifier. So, for your test script to click this button you simply need to use the following Selenium command.

click adminHomeForm

Or, in Selenium 1.0

selenium.click("adminHomeForm");

Your application, however, may generate HTML dynamically where the identifier varies on different instances of the webpage. For instance, HTML for a dynamic page element might look like this.

<input type="checkbox" value="true" id="addForm:_ID74:_ID75:0:_ID79:0:checkBox" name="addForm:_ID74:_ID75:0:_ID79:0:checkBox"/>

This defines a checkbox. Its ID and name attributes (both addForm:_ID74:_ID75:0:_ID79:0:checkBox) are dynamically generated values. In this case, using a standard locator would look something like the following.

click addForm:_ID74:_ID75:0:_ID79:0:checkBox

Or, again in Selenium-RC

selenium.click("addForm:_ID74:_ID75:0:_ID79:0:checkBox");

Given the dynamically generated Identifier, this approach would not work. The next time this page is loaded the Identifier will be a different value from the one used in the Selenium command and therefore, will not be found. The click operation will fail with an “element not found” error.

To correct this, a simple solution would be to just use an XPath locator rather than trying to use an ID locator. So, for the checkbox you can simply use

click //input

Or, if it is not the first input element on the page (which it is likely not) try a more detailed XPath statement.

click //input[3]

Or

click //div/p[2]/input[3]

If however, you do need to use the ID to locate the element, a different solution is needed. You can capture this ID from the website before you use it in a Selenium command. It can be done like this.

String[] checkboxids = selenium.getAllFields(); // Collect all input IDs on page.

for(String checkboxid:checkboxids) { 
  if(checkboxid.contains("addForm")) { 
    selenium.click(checkboxid); 
  }
}

This approach will work if there is only one check box whose ID contains the text ‘addForm’.

Locating Ajax Elements

As was presented in the Types of Tests subsection above, a page element implemented with Ajax is an element that can be dynamically refreshed without having to refresh the entire page. The best way to locate and verify an Ajax element is to use the Selenium 2.0 WebDriver API. It was specifically designed to address testing of Ajax elements where Selenium 1 has some limitations.

In Selenium 2.0 you use the waitFor() method to wait for a page element to become available. The parameter is a By object which is how WebDriver implements locators. This is explained in detail in the WebDriver chapters.

To do this with Selenium 1.0 (Selenium-RC) a bit more coding is involved, but it isn’t difficult. The approach is to check for the element, if it’s not available wait for a predefined period and then again recheck it. This is then executed with a loop with a predetermined time-out terminating the loop if the element isn’t found.

Let’s consider a page which brings a link (link=ajaxLink) on click of a button on page (without refreshing the page). This could be handled by Selenium using a for loop.

// Loop initialization.
for (int second = 0;; second++) { 

  // If loop reached 60 seconds then break the loop. 
  if (second >= 60) break; 

  // Search for element "link=ajaxLink" and if available then break loop. 
  try { if (selenium.isElementPresent("link=ajaxLink")) break; } catch (Exception e) {} 

  // Pause for 1 second. 
  Thread.sleep(1000);
}

This certainly isn’t the only solution. Ajax is a common topic in the user forum and we recommend searching previous discussions to see what others have done.

Wrapping Selenium Calls

As with any programming, you will want to use utility functions to handle code that would otherwise be duplicated throughout your tests. One way to prevent this is to wrap frequently used selenium calls with functions or class methods of your own design. For example, many tests will frequently click on a page element and wait for page to load multiple times within a test.

selenium.click(elementLocator);
selenium.waitForPageToLoad(waitPeriod);

Instead of duplicating this code you could write a wrapper method that performs both functions.

/** 
  * Clicks and Waits for page to load. 
  * 
  * param elementLocator 
  * param waitPeriod 
  */
public void clickAndWait(String elementLocator, String waitPeriod) { 
  selenium.click(elementLocator); 
  selenium.waitForPageToLoad(waitPeriod);
}

‘Safe Operations’ for Element Presence

Another common usage of wrapping Selenium methods is to check for presence of an element on a page before carrying out some operation. This is sometimes called a ‘safe operation’. For instance, the following method could be used to implement a safe operation that depends on an expected element being present.

/** 
  * Selenum-RC -- Clicks on an element only if it is available on a page. 
  * 
  * param elementLocator 
  */
public void safeClick(String elementLocator) { 
  if(selenium.isElementPresent(elementLocator)) { 
    selenium.click(elementLocator); 
  } else { 
    // Using the TestNG API for logging 
    Reporter.log("Element: " + elementLocator + ", is not available on a page - " 
      +selenium.getLocation()); 
   }
}

This example uses the Selenium 1 API but Selenium 2 also supports this.

/** 
  * Selenium-WebDriver -- Clicks on an element only if it is available on a page. 
  * 
  * param elementLocator 
  */
 public void safeClick(String elementLocator) { 
  WebElement webElement = getDriver().findElement(By.XXXX(elementLocator)); 
  if(webElement != null) { 
    selenium.click(webElement); 
  } else { 
    // Using the TestNG API for logging 
    Reporter.log("Element: " + elementLocator + ", is not available on a page - " 
      + getDriver().getUrl()); 
  }
 }

In this second example ‘XXXX’ is simply a placeholder for one of the multiple location methods that can be called here.

Using safe methods is up to the test developer’s discretion. Hence, if test execution is to be continued, even in the wake of missing elements on the page, then safe methods could be used, while posting a message to a log about the missing element. This, essentially, implements a ‘verify’ with a reporting mechanism as opposed to an abortive assert. But if an element must be available on a page in order to be able to carry out further operations (i.e. login button on home page of a portal) then this safe method technique should not be used.

UI Mapping

A UI Map is a mechanism that stores all the locators for a test suite in one place for easy modification when identifiers or paths to UI elements change in the AUT. The test script then uses the UI Map for locating the elements to be tested. Basically, a UI map is a repository of test script objects that correspond to UI elements of the application being tested.

What makes a UI map helpful? Its primary purpose is making test script management much easier. When a locator needs to be edited, there is a central location for easily finding that object, rather than having to search through test script code. Also, it allows changing the Identifier in a single place, rather than having to make the change in multiple places within a test script, or for that matter, in multiple test scripts.

To summarize, a UI Map has two significant advantages
- Using a centralized location for UI objects instead of having them scattered throughout the script. This makes script maintenance more efficient.
- Cryptic HTML Identifiers and names can be given more human-readable names improving the readability of test scripts.

Consider the following, difficult to understand, example (in Java).

public void testNew() throws Exception { 
  selenium.open("http://www.test.com"); 
  selenium.type("loginForm:tbUsername", "xxxxxxxx"); 
  selenium.click("loginForm:btnLogin"); 
  selenium.click("adminHomeForm:_activitynew"); 
  selenium.waitForPageToLoad("30000"); 
  selenium.click("addEditEventForm:_IDcancel"); 
  selenium.waitForPageToLoad("30000"); 
  selenium.click("adminHomeForm:_activityold"); 
  selenium.waitForPageToLoad("30000");
}

This script would be hard to follow for anyone not familiar with the AUT’s page source. Even regular users of the application might have difficulties in understanding what this script does. A better script could be:

public void testNew() throws Exception { 
  selenium.open("http://www.test.com"); 
  selenium.type(admin.username, "xxxxxxxx"); 
  selenium.click(admin.loginbutton); 
  selenium.click(admin.events.createnewevent); 
  selenium.waitForPageToLoad("30000"); 
  selenium.click(admin.events.cancel); 
  selenium.waitForPageToLoad("30000"); 
  selenium.click(admin.events.viewoldevents); 
  selenium.waitForPageToLoad("30000");
}

Now, using some comments and whitespace along with the UI Map identifiers makes a very readable script.

public void testNew() throws Exception { 

  // Open app url. 
  selenium.open("http://www.test.com"); 

  // Provide admin username. 
  selenium.type(admin.username, "xxxxxxxx"); 

  // Click on Login button. 
  selenium.click(admin.loginbutton); 

  // Click on Create New Event button. 
  selenium.click(admin.events.createnewevent); 
  selenium.waitForPageToLoad("30000"); 

  // Click on Cancel button. 
  selenium.click(admin.events.cancel); 
  selenium.waitForPageToLoad("30000"); 

  // Click on View Old Events button. 
  selenium.click(admin.events.viewoldevents); 
  selenium.waitForPageToLoad("30000");
}

There are various ways a UI Map can be implemented. One could create a class or struct which only stores public String variables each storing a locator. Alternatively, a text file storing key value pairs could be used. In Java, a properties file containing key/value pairs is probably the best method.

Consider a properties file prop.properties which assigns as ‘aliases’ reader-friendly identifiers for UI elements from the previous example.

admin.username = loginForm:tbUsername
admin.loginbutton = loginForm:btnLogin
admin.events.createnewevent = adminHomeForm:_activitynew
admin.events.cancel = addEditEventForm:_IDcancel
admin.events.viewoldevents = adminHomeForm:_activityold

The locators will still refer to HTML objects, but we have introduced a layer of abstraction between the test script and the UI elements. Values are read from the properties file and used in the Test Class to implement the UI Map. For more on Java properties files refer to the following link.

Page Object Design Pattern

Page Object is a Design Pattern which has become popular in test automation for enhancing test maintenance and reducing code duplication. A page object is an object-oriented class that serves as an interface to a page of your AUT. The tests then use the methods of this page object class whenever they need to interact with the UI of that page. The benefit is that if the UI changes for the page, the tests themselves don’t need to change, only the code within the page object needs to change. Subsequently all changes to support that new UI are located in one place.

The Page Object Design Pattern provides the following advantages

  1. There is a clean separation between test code and page specific code such as locators (or their use if you’re using a UI Map) and layout.
  2. There is a single repository for the services or operations offered by the page rather than having these services scattered throughout the tests.

In both cases this allows any modifications required due to UI changes to all be made in one place. Useful information on this technique can be found on numerous blogs as this ‘test design pattern’ is becoming widely used. We encourage the reader who wishes to know more to search the internet for blogs on this subject. Many have written on this design pattern and can provide useful tips beyond the scope of this user guide. To get you started, though, we’ll illustrate page objects with a simple example.

First, consider an example, typical of test automation, that does not use a page object.

/*** 
  * Tests login feature 
  */
public class Login { 
  public void testLogin() { 
    selenium.type("inputBox", "testUser"); 
    selenium.type("password", "my supersecret password"); 
    selenium.click("sign-in"); 
    selenium.waitForPageToLoad("PageWaitPeriod");
    Assert.assertTrue(selenium.isElementPresent("compose button"), 
      "Login was unsuccessful"); 
  }
}

There are two problems with this approach.

  1. There is no separation between the test method and the AUT’s locators (IDs in this example); both are intertwined in a single method. If the AUT’s UI changes its identifiers, layout, or how a login is input and processed, the test itself must change.
  2. The ID-locators would be spread in multiple tests, in all tests that had to use this login page.

Applying the page object techniques, this example could be rewritten like this in the following example of a page object for a Sign-in page.

/** 
  * Page Object encapsulates the Sign-in page. 
  */
public class SignInPage { 

  private Selenium selenium; 

  public SignInPage(Selenium selenium) { 
    this.selenium = selenium; 
    if(!selenium.getTitle().equals("Sign in page")) { 
      throw new IllegalStateException("This is not sign in page, current page is: "
        +selenium.getLocation()); 
     } 
   } 
   /** 
     * Login as valid user 
     * 
     * @param userName 
     * @param password 
     * @return HomePage object 
     */ 
  public HomePage loginValidUser(String userName, String password) {
    selenium.type("usernamefield", userName); 
    selenium.type("passwordfield", password);
    selenium.click("sign-in"); 
    selenium.waitForPageToLoad("waitPeriod");

    return new HomePage(selenium); 
  }
}

and page object for a Home page could look like this.

/** 
  * Page Object encapsulates the Home Page 
  */
public class HomePage { 

  private Selenium selenium; 

  public HomePage(Selenium selenium) { 
    if (!selenium.getTitle().equals("Home Page of logged in user")) { 
      throw new IllegalStateException("This is not Home Page of logged in user, current page" + 
        "is: " +selenium.getLocation()); 
      } 
    } 

   public HomePage manageProfile() { 
     // Page encapsulation to manage profile functionality 
     return new HomePage(selenium); 
   } 

   /*More methods offering the services represented by Home Page 
   of Logged User. These methods in turn might return more Page Objects 
   for example click on Compose mail button could return ComposeMail class object*/
}

So now, the login test would use these two page objects as follows.

/*** 
  * Tests login feature 
  */
public class TestLogin { 

  public void testLogin() { 
    SignInPage signInPage = new SignInPage(selenium); 
    HomePage homePage = signInPage.loginValidUser("userName", "password");
    Assert.assertTrue(selenium.isElementPresent("compose button"), 
      "Login was unsuccessful"); 
  }
}

There is a lot of flexibility in how the page objects may be designed, but there are a few basic rules for getting the desired maintainability of your test code.

Page objects themselves should never make verifications or assertions. This is part of your test and should always be within the test’s code, never in an page object. The page object will contain the representation of the page, and the services the page provides via methods but no code related to what is being tested should be within the page object.

There is one, single, verification which can, and should, be within the page object and that is to verify that the page, and possibly critical elements on the page, were loaded correctly. This verification should be done while instantiating the page object. In the examples above, both the SignInPage and HomePage constructors check that the expected page is available and ready for requests from the test.

A page object does not necessarily need to represent an entire page. The Page Object design pattern could be used to represent components on a page. If a page in the AUT has multiple components, it may improve maintainability if there is a separate page object for each component.

There are other design patterns that also may be used in testing. Some use a Page Factory for instantiating their page objects. Discussing all of these is beyond the scope of this user guide. Here, we merely want to introduce the concepts to make the reader aware of some of the things that can be done. As was mentioned earlier, many have blogged on this topic and we encourage the reader to search for blogs on these topics.

Data Driven Testing

Data Driven Testing refers to using the same test (or tests) multiple times with varying data. These data sets are often from external files i.e. .csv file, text file, or perhaps loaded from a database. Data driven testing is a commonly used test automation technique used to validate an application against many varying inputs. When the test is designed for varying data, the input data can expand, essentially creating additional tests, without requiring changes to the test code.

In Python:

# Collection of String values
source = open("input_file.txt", "r")
values = source.readlines()
source.close()
# Execute For loop for each String in the values array
for search in values: 
  driver.get('http://www.google.com') 
  driver.find_element_by_name("q").send_keys(search) 
  driver.find_element_by_id("btnG").click() 
  element = WebDriverWait(driver, 5).until(ExpectedConditions.presence_of_element_located((By.XPATH, "//*[contains(., 'Results')]"))
  assert search in element.text

The Python script above opens a text file. This file contains a different search string on each line. The code then saves this in an array of strings, and iterates over the array doing a search and assert on each string.

This is a very basic example, but the idea is to show that running a test with varying data can be done easily with a programming or scripting language. Additionally, this is a well-known topic among test automation professionals including those who don’t use Selenium so searching the internet on “data-driven testing” should reveal many blogs on this topic.

Database Validation

Another common type of testing is to compare data in the UI against the data actually stored in the AUT’s database. Since you can also do database queries from a programming language, assuming you have database support functions, you can use them to retrieve data and then use the data to verify what’s displayed by the AUT is correct.

Consider the example of a registered email address to be retrieved from a database and then later compared against the UI. An example of establishing a DB connection and retrieving data from the DB could look like this.

In Java:

// Load Microsoft SQL Server JDBC driver.
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

// Prepare connection url.
String url = "jdbc:sqlserver://192.168.1.180:1433;DatabaseName=TEST_DB";

// Get connection to DB.
public static Connection con =
DriverManager.getConnection(url, "username", "password");

// Create statement object which would be used in writing DDL and DML
// SQL statement.
public static Statement stmt = con.createStatement();

// Send SQL SELECT statements to the database via the Statement.executeQuery
// method which returns the requested information as rows of data in a
// ResultSet object.

ResultSet result = stmt.executeQuery
("select top 1 email_address from user_register_table");

// Move cursor from default position to first row of result set.
result.next();

// Fetch value of "email_address" from "result" object.
String emailaddress = result.getString("email_address");

// Use the emailAddress value to login to application.
driver.findElement(By.id, "userID").sendKeys(emailaddress);
driver.findElement(By.id, "password").sendKeys(secretPassword);
driver.findElement(By.id, "loginButton").click();
WebElement element = driver.findElement(By.xpath, "//*[contains(.,'Welcome back ')]");
Assert.assertTrue(element.getText().contains(emailaddress), "Unable to log in for user" + emailaddress)

This is a simple Java example of data retrieval from a database.

内容概要:文章以“智能网页数据标注工具”为例,深入探讨了谷歌浏览器扩展在毕业设计中的实战应用。通过开发具备实体识别、情感分类等功能的浏览器扩展,学生能够融合前端开发、自然语言处理(NLP)、本地存储与模型推理等技术,实现高效的网页数据标注系统。文中详细解析了扩展的技术架构,涵盖Manifest V3配置、内容脚本与Service Worker协作、TensorFlow.js模型在浏览器端的轻量化部署与推理流程,并提供了核心代码实现,包括文本选择、标注工具栏动态生成、高亮显示及模型预测功能。同时展望了多模态标注、主动学习与边缘计算协同等未来发展方向。; 适合人群:具备前端开发基础、熟悉JavaScript和浏览器机制,有一定AI模型应用经验的计算机相关专业本科生或研究生,尤其适合将浏览器扩展与人工智能结合进行毕业设计的学生。; 使用场景及目标:①掌握浏览器扩展开发全流程,理解内容脚本、Service Worker与弹出页的通信机制;②实现在浏览器端运行轻量级AI模型(如NER、情感分析)的技术方案;③构建可用于真实场景的数据标注工具,提升标注效率并探索主动学习、协同标注等智能化功能。; 阅读建议:建议结合代码实例搭建开发环境,逐步实现标注功能并集成本地模型推理。重点关注模型轻量化、内存管理与DOM操作的稳定性,在实践中理解浏览器扩展的安全机制与性能优化策略。
基于Gin+GORM+Casbin+Vue.js的权限管理系统是一个采用前后端分离架构的企业级权限管理解决方案,专为软件工程和计算机科学专业的毕业设计项目开发。该系统基于Go语言构建后端服务,结合Vue.js前端框架,实现了完整的权限控制和管理功能,适用于各类需要精细化权限管理的应用场景。 系统后端采用Gin作为Web框架,提供高性能的HTTP服务;使用GORM作为ORM框架,简化数据库操作;集成Casbin实现灵活的权限控制模型。前端基于vue-element-admin模板开发,提供现代化的用户界面和交互体验。系统采用分层架构和模块化设计,确保代码的可维护性和可扩展性。 主要功能包括用户管理、角色管理、权限管理、菜单管理、操作日志等核心模块。用户管理模块支持用户信息的增删改查和状态管理;角色管理模块允许定义不同角色并分配相应权限;权限管理模块基于Casbin实现细粒度的访问控制;菜单管理模块动态生成前端导航菜单;操作日志模块记录系统关键操作,便于审计和追踪。 技术栈方面,后端使用Go语言开发,结合Gin、GORM、Casbin等成熟框架;前端使用Vue.js、Element UI等现代前端技术;数据库支持MySQL、PostgreSQL等主流关系型数据库;采用RESTful API设计规范,确保前后端通信的标准化。系统还应用了单例模式、工厂模式、依赖注入等设计模式,提升代码质量和可测试性。 该权限管理系统适用于企业管理系统、内部办公平台、多租户SaaS应用等需要复杂权限控制的场景。作为毕业设计项目,它提供了完整的源码和论文文档,帮助学生深入理解前后端分离架构、权限控制原理、现代Web开发技术等关键知识点。系统设计规范,代码结构清晰,注释完整,非常适合作为计算机相关专业的毕业设计参考或实际项目开发的基础框架。 资源包含完整的系统源码、数据库设计文档、部署说明和毕
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值