I think you listed the differences very well in your question, however I'll add some of my opinions regarding the two approaches.
AAA is very useful for me when I'm testing my own code. If I'm working on a project or a library for myself, AAA is the way that I go. It lets me set up whatever I need to execute my test and then just test it. It's quick to setup, and quick to verify that my code is working as I expect.
GWT is useful in business environments, where work that is done by programmers needs to be mapped to business value. Business value is mapped by features, and hopefully features that don't introduce bugs. There are many strategies for mapping features to programming tasks, but one of them is through requirements. In my experience, requirements range from user-level requirements all the way down to small tasks for the user to execute. This is useful because it's easy for the managers to understand how the work the programmer is doing is impacting their customers/users, and therefore why the programmers are adding value to their business
- User-Level Requirement: Given the warehouse has at least N item(s) in inventory, when a user purchases N item(s), then the warehouse ships N item(s) to the user
- System-Level Requirement 1: Given the inventory system has N item(s) in inventory, when a request for N item(s) is input into the inventory system then the inventory system decreases the inventory count for that type of item
- System-Level Requirement 2: Given the payment system has N item(s) in inventory, when a request for N item(s) is input into the payment system then the payment system charges the user for N item(s)
- ...
- Programmer-Level Requirement 1: Given 5 sweaters are in inventory, when 3 sweaters are removed from inventory then 2 sweaters are left in the inventory
- ...
This sort of requirement structure allows for a tree-like design where all of the Programmer-Level Requirements map up the tree to the User-Level Requirements. In this way, when a Programmer-Level Requirement fails then you know which User-Level Requirement is affected.
In contrast, an AAA test might look like this. This to me is very programmer-facing and not useful to the business. That's not to say a similar tree structure of requirements couldn't be made from an AAA testing strategy, but nothing in the language of AAA makes it easier to do so.
public void Test_CaseWhereThereAreEnoughSweatersLeft() {
// Arrange
// setup Sweater Inventory mock (DB mocks, etc)
// count = 5
// when The number of sweaters remaining is request, return count
// when Inventory is requested to remove N items, then count = count - N
// Act
// call the Unit Under Test to remove 3 items from inventory
// Assert
// the number of sweaters in the inventory is 2
// the removal should return indicating a successful removal of items from the inventory
}
public void Test_CaseWhereThereAreNotEnoughSweatersLeft() {
// Arrange
// setup Sweater Inventory mock (DB mocks, etc)
// count = 2
// when The number of sweaters remaining is request, return count
// when Inventory is requested to remove N items, then count = count - N
// Act
// call the Unit Under Test to remove 3 items from inventory
// Assert
// the number of sweaters remaining is still 2
// the removal should return an error indicating not enough items in the inventory
}