Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 24 additions & 14 deletions .cursor/rules/testing-patterns.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,35 @@ description: Testing patterns and conventions
globs: "**/Tests/**,**/*Test*.cs"
alwaysApply: false
---
# Testing Patterns
**Location**: `StellarDotnetSdk.Tests/`, mirror SDK structure. Name: `<Class>Test.cs`.

**Location**: `StellarDotnetSdk.Tests/`, mirror `StellarDotnetSdk/` structure. Name: `<Class>Test.cs`.
**Frameworks**: MSTest, Moq, FluentAssertions.

**Frameworks**: MSTest (`[TestClass]`, `[TestMethod]`), Moq (`Mock<T>`), FluentAssertions.
## Test Naming

**AAA (unit tests)**: Group code into `// Arrange`, `// Act`, `// Assert` sections.
Pattern: `[Method]_[Scenario]_[Result]`

**Mocking**: `var mock = new Mock<IInterface>(); mock.Setup(x => x.Method()).ReturnsAsync(value);`. Use `It.IsAny<T>()` for flexible matching.
| ❌ Avoid | ✅ Preferred |
|----------|-------------|
| `TestSign` | `Sign_ValidData_ReturnsSignature` |
| `TestVerifyFalse` | `Verify_InvalidSignature_ReturnsFalse` |
| `TestFromSecretSeed` | `FromSecretSeed_ValidSeed_ReturnsKeyPair` |

**FluentAssertions**: `response.Should().NotBeNull(); response.IsSuccess.Should().BeTrue();`
Common patterns:
- `Method_ValidInput_ReturnsExpected` (happy path)
- `Method_NullInput_ThrowsArgumentNull` (edge case)
- `Method_WhenDisposed_ThrowsObjectDisposed` (state)

**Test data**: JSON files in `TestData/` folder, loaded via `Utils.CreateTestServerWithJson()`.
**Don'ts**: No `Test` prefix, no vague names, describe behavior not implementation.

**Documentation**: Add `/// <summary>` XML docs to test methods. Two sentences e.g.:
```
/// Tests [what the test is for]
/// Verifies [what it verifies]
```
Focus on behavior, not implementation.
## Structure

**Commands**: `dotnet test` (all) | `dotnet test --filter "FullyQualifiedName~ClassName"` (specific).
**AAA**: `// Arrange`, `// Act`, `// Assert` sections.

**Mocking**: `new Mock<T>()`, `Setup().ReturnsAsync()`. `It.IsAny<T>()` for flexible matching.

**Assertions**: FluentAssertions (`Should().NotBeNull()`, `Should().BeTrue()`).

**Test data**: JSON in `TestData/`, load via `Utils.CreateTestServerWithJson()`.

**Run**: `dotnet test` | `dotnet test --filter "FullyQualifiedName~ClassName"`.
11 changes: 9 additions & 2 deletions StellarDotnetSdk.Tests/Accounts/AccountFlagTest.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StellarDotnetSdk.Accounts;

namespace StellarDotnetSdk.Tests.Accounts;

/// <summary>
/// Unit tests for <see cref="AccountFlag" /> enum.
/// </summary>
[TestClass]
public class AccountFlagTest
{
/// <summary>
/// Verifies that AccountFlag enum values are correct.
/// </summary>
[TestMethod]
public void TestValues()
public void AccountFlag_Values_AreCorrect()
{
// Act & Assert
Assert.AreEqual(1, (int)AccountFlag.AUTH_REQUIRED_FLAG);
Assert.AreEqual(2, (int)AccountFlag.AUTH_REVOCABLE_FLAG);
Assert.AreEqual(4, (int)AccountFlag.AUTH_IMMUTABLE_FLAG);
Expand Down
59 changes: 52 additions & 7 deletions StellarDotnetSdk.Tests/Accounts/AccountTest.cs
Original file line number Diff line number Diff line change
@@ -1,66 +1,111 @@
using System;
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StellarDotnetSdk.Accounts;

namespace StellarDotnetSdk.Tests.Accounts;

/// <summary>
/// Unit tests for <see cref="Account" /> class.
/// </summary>
[TestClass]
public class AccountTest
{
/// <summary>
/// Verifies that Account constructor throws ArgumentNullException when arguments are null.
/// </summary>
[TestMethod]
public void TestNullArguments()
public void Constructor_WithNullArguments_ThrowsArgumentNullException()
{
// Act & Assert
Assert.ThrowsException<ArgumentNullException>(() => new Account((string)null, 10L));

Check warning on line 20 in StellarDotnetSdk.Tests/Accounts/AccountTest.cs

View workflow job for this annotation

GitHub Actions / pack_and_test

Cannot convert null literal to non-nullable reference type.

Check warning on line 20 in StellarDotnetSdk.Tests/Accounts/AccountTest.cs

View workflow job for this annotation

GitHub Actions / pack_and_test

Converting null literal or possible null value to non-nullable type.
Comment thread
jopmiddelkamp marked this conversation as resolved.
Assert.ThrowsException<ArgumentNullException>(() => new Account(KeyPair.Random().AccountId, null));
}

/// <summary>
/// Verifies that Account constructor with string argument creates account with correct KeyPair.
/// </summary>
[TestMethod]
public void TestWithStringArgumentIsKeyPair()
public void Constructor_WithStringArgument_CreatesAccountWithCorrectKeyPair()
{
// Arrange
var keypair = KeyPair.Random();

// Act
var account = new Account(keypair.Address, 7);

// Assert
Assert.AreEqual(account.AccountId, keypair.AccountId);
Assert.AreEqual(account.KeyPair.AccountId, keypair.AccountId);
}

/// <summary>
/// Verifies that Account constructor with muxed account creates account with correct account ID and key pair.
/// </summary>
[TestMethod]
public void TestWithMuxedAccount()
public void Constructor_WithMuxedAccount_CreatesAccountWithCorrectAccountId()
{
// Arrange
var keypair = KeyPair.Random();
var muxed = new MuxedAccountMed25519(keypair, 10);

// Act
var account = new Account(muxed, 7);

// Assert
Assert.AreNotEqual(account.AccountId, keypair.AccountId);
Assert.AreEqual(account.AccountId, muxed.AccountId);
Assert.AreEqual(account.KeyPair.AccountId, keypair.AccountId);
}

/// <summary>
/// Verifies that IncrementedSequenceNumber returns incremented value without modifying account sequence number.
/// </summary>
[TestMethod]
public void TestGetIncrementedSequenceNumber()
public void IncrementedSequenceNumber_ReturnsIncrementedValue_WithoutModifyingAccount()
Comment thread
jopmiddelkamp marked this conversation as resolved.
{
// Arrange
var random = KeyPair.Random();
var account = new Account(random.AccountId, 100L);

// Act
var incremented = account.IncrementedSequenceNumber;

// Assert
Assert.AreEqual(100L, account.SequenceNumber);
Assert.AreEqual(101L, incremented);
incremented = account.IncrementedSequenceNumber;
Assert.AreEqual(100L, account.SequenceNumber);
Assert.AreEqual(101L, incremented);
}

/// <summary>
/// Verifies that IncrementSequenceNumber increments the account sequence number.
/// </summary>
[TestMethod]
public void TestIncrementSequenceNumber()
public void IncrementSequenceNumber_IncrementsSequenceNumber()
{
// Arrange
var random = KeyPair.Random();
var account = new Account(random.AccountId, 100L);

// Act
account.IncrementSequenceNumber();

// Assert
Assert.AreEqual(account.SequenceNumber, 101L);
}

/// <summary>
/// Verifies that Account getters return correct values.
/// </summary>
[TestMethod]
public void TestGetters()
public void Getters_ReturnCorrectValues()
{
// Arrange
var keypair = KeyPair.Random();
var account = new Account(keypair.AccountId, 100L);

// Act & Assert
Assert.AreEqual(account.KeyPair.AccountId, keypair.AccountId);
Assert.AreEqual(account.AccountId, keypair.AccountId);
Assert.AreEqual(account.SequenceNumber, 100L);
Expand Down
Loading
Loading