You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Moq单元测试空引用异常解决及徽章方法测试咨询

Testing the Badge Method with Moq & Fixing Null Reference Errors

First, let's break down what we need to accomplish: verify that your Badge method creates and adds a new PlayerBadge when one doesn't exist for the given pID and bID. The "Object reference not set to an instance of an object" error almost always stems from improperly mocking your EliminationDbContext or its PlayerBadges DbSet.

Step 1: Mock the DbContext and DbSet

To make your query logic work with Moq, you need to set up a mock DbSet that supports queryable operations (like Where and Any). Here's a reusable helper method to create a mock DbSet from a list:

private static Mock<DbSet<T>> CreateMockDbSet<T>(List<T> data) where T : class
{
    var queryableData = data.AsQueryable();
    var mockSet = new Mock<DbSet<T>>();
    
    // Set up queryable behavior
    mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryableData.Provider);
    mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryableData.Expression);
    mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryableData.ElementType);
    mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator());
    
    // Track additions to the list
    mockSet.Setup(m => m.Add(It.IsAny<T>())).Callback<T>(data.Add);
    
    return mockSet;
}

Step 2: Write the Unit Test for Adding a New Badge

Let's build a test that verifies the method adds a new PlayerBadge when none exists. We'll cover setup, execution, and assertions:

[Test]
public void Badge_WhenPlayerBadgeDoesNotExist_AddsNewEntry()
{
    // Arrange
    var testPlayerId = 1;
    var testBadgeId = 2;
    var testGameId = 3;
    
    // Start with an empty list of PlayerBadges
    var playerBadges = new List<PlayerBadge>();
    var mockPlayerBadgesSet = CreateMockDbSet(playerBadges);
    
    // Mock the DbContext to return our mock DbSet
    var mockContext = new Mock<EliminationDbContext>();
    mockContext.Setup(c => c.PlayerBadges).Returns(mockPlayerBadgesSet.Object);
    
    // Instantiate your service/class (replace with your actual class name)
    var badgeManager = new BadgeManager(mockContext.Object);
    
    // Act
    var result = badgeManager.Badge(testPlayerId, testBadgeId, testGameId);
    
    // Assert
    // Check the method returned success (assuming true means success)
    Assert.IsTrue(result);
    
    // Verify one new badge was added
    Assert.AreEqual(1, playerBadges.Count);
    
    // Confirm the new badge has the correct properties
    var addedBadge = playerBadges.First();
    Assert.AreEqual(testPlayerId, addedBadge.PlayerID); // Adjust to match your model's property name
    Assert.AreEqual(testBadgeId, addedBadge.BadgeID);
    Assert.AreEqual(testGameId, addedBadge.GameID);
    
    // Ensure the Add method was called exactly once
    mockPlayerBadgesSet.Verify(m => m.Add(It.IsAny<PlayerBadge>()), Times.Once);
}

Fixing the Null Reference Error

This error typically occurs for one of these reasons:

  • Unmocked DbSet: If you forget to set up mockContext.Setup(c => c.PlayerBadges).Returns(...), PlayerBadges will be null when your method tries to access it.
  • Null navigation properties: If your query uses x.Player.PlayerID or x.Badge.BadgeID on existing entries, you need to initialize those navigation properties in your mock data. For example:
    var existingBadge = new PlayerBadge 
    { 
        Player = new Player { PlayerID = testPlayerId }, 
        Badge = new Badge { BadgeID = testBadgeId } 
    };
    
  • Hardcoded DbContext instance: If your class creates a new EliminationDbContext instead of using dependency injection, your mock won't be used—leading to null references or real database calls.

Testing the Case Where the Badge Already Exists

Don't forget to test the opposite scenario: when the badge exists, the method shouldn't add a new one:

[Test]
public void Badge_WhenPlayerBadgeExists_DoesNotAddNewEntry()
{
    // Arrange
    var testPlayerId = 1;
    var testBadgeId = 2;
    
    var existingBadge = new PlayerBadge 
    { 
        PlayerID = testPlayerId, 
        BadgeID = testBadgeId 
    };
    var playerBadges = new List<PlayerBadge> { existingBadge };
    var mockPlayerBadgesSet = CreateMockDbSet(playerBadges);
    
    var mockContext = new Mock<EliminationDbContext>();
    mockContext.Setup(c => c.PlayerBadges).Returns(mockPlayerBadgesSet.Object);
    
    var badgeManager = new BadgeManager(mockContext.Object);
    
    // Act
    var result = badgeManager.Badge(testPlayerId, testBadgeId);
    
    // Assert
    // Assuming false means the badge already exists
    Assert.IsFalse(result);
    
    // Verify no new badges were added
    Assert.AreEqual(1, playerBadges.Count);
    
    // Ensure Add was never called
    mockPlayerBadgesSet.Verify(m => m.Add(It.IsAny<PlayerBadge>()), Times.Never);
}

Key Takeaways

  • Always mock DbSets with queryable behavior to support LINQ operations like Where and Any.
  • Use dependency injection to pass the mock context to your class—avoid hardcoding context instances.
  • Initialize navigation properties in mock data if your query relies on them.
  • Verify both the method's return value and side effects (like Add being called) to ensure full coverage.

内容的提问来源于stack exchange,提问作者hmad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:32:04