Posts in category “Programming”

Moq Tips 2 - check if a log message with a specific prefix/suffix and call a method with an object having a specific field value

  1. To check if a log message with a specific prefix is logged, you can use Moq's Verify method along with an appropriate assertion.
_logger.Verify(logger => logger.logInformation(
    It.Is<string>(s => s.StartsWith("specific prefix"))), Times.Once);
  1. To verify that a method is called with an object containing a specific property value, you can use Moq's It.Is<T> matcher along with a lambda expression. Here's an example:

    _mockObject.Verify(x => x.MyMethod(It.Is<MyObject>(
     obj => obj.PropertyValue == expectedPropertyValue)), Times.Once);
    
  2. Correctly returns null: Sometimes we need to set up a Moq mock to return null but cannot directly do it as Moq doesn't allow. Please check the following way that you should use:

_bookStoreAccountRepository.Setup(
    b => b.GetBookStoreAccountByUserName(It.IsAny<string>()))
    .Returns((BookStoreAccount)null);

The key is to use (BookStoreAccount)null to explicitly cast null to the expected return type.

Moq tips 1 - learn how to write unit tests from ChatGPT

When should I use mockObject.Reset() and when should I use mockObject.Invocations.Clear()?

In the context of using a mocking framework like Moq in C# for unit testing, the choice between mockObject.Reset() and mockObject.Invocations.Clear() depends on what you want to achieve.

  1. mockObject.Reset():

    • This is specific to the Moq library.
    • It resets the mock object, removing any setups or custom behavior you might have defined for that mock.
    • It does not clear recorded invocations; you can still access them after calling Reset().

    Example:

    var mock = new Mock<MyClass>();
    mock.Setup(x => x.MyMethod()).Returns("Original");
       
    // ... code using the mock ...
       
    // Reset the mock, removing setups
    mock.Reset();
       
    // Now, if you call the method, it won't use the previous setup
    var result = mock.Object.MyMethod();
    
  2. mockObject.Invocations.Clear():

    • This clears the recorded invocations on the mock object.
    • It doesn't affect setups or custom behavior. It just removes the history of invocations.
    • This can be useful when you want to verify interactions or check the number of invocations without interference from previous test runs.

    Example:

   var mock = new Mock<MyClass>();
   mock.Setup(x => x.MyMethod()).Returns("Original");
   
   // ... code using the mock ...
   
   // Clear recorded invocations
   mock.Invocations.Clear();
   
   // Now, if you verify invocations, it won't consider previous calls
   mock.Verify(x => x.MyMethod(), Times.Never());

In summary:

  • Use mockObject.Reset() when you want to clear setups and start fresh with the mock.
  • Use mockObject.Invocations.Clear() when you want to clear the history of invocations, but keep the existing setups and behaviors.

If I set up a method with the same parameters multiple times, the last setup will take effect, right?

In most mocking frameworks, including Moq for C#, the answer is YES. Each new setup for the same method and parameters overrides any previous setups.

Here's an example using Moq:


// Setting up the method with the same parameters but different returns
mock.Setup(x => x.MyMethod()).Returns("FirstSetup");
mock.Setup(x => x.MyMethod()).Returns("SecondSetup");

// Now, if you call the method, it will return "SecondSetup"
var result = mock.Object.MyMethod();

A neat way to remove trailing zeros from a decimal number in C#

We can get unexpected trailing zeros when we serialzie an object with decimal properties, normally it will not hurt. However, it does hurt when we want to compare two objects by serializing them to JSON string. I tried a few solutions and finally find the following one is the best.

public static decimal Normalize(this decimal value)
{
    return value/1.000000000000000000000000000000000m;
}

Reference

发布 Game scripting mastery 中文精要 - 第八章

Game scripting mastery 是一本不可多得的好书,除了写得啰嗦。

豆瓣网友 全棧法師张解靈 2018-08-01 16:37:13 写道:
说实话,难看。 但是内容完全没问题,就是实在太啰嗦了,即使英语原著也是...看得有点难受,想跳呢又怕错过好东西,想慢慢看呢又...还是慢慢啃吧 如果谁重排一个脱水版,我绝对打满分

另一个网友 TerryX 2017-01-06 18:44:19 写道:
这本书可以说是被严重低估,可能因为这个专职院校味道的书名。从第9章开始简直不能再好,从编译器底层到高级虚拟机一气呵成。这本书真不仅仅是教你做游戏,而是教你怎么成为master。

所以我启动了这个脱水版项目:初步计划是从第8章开始到全书结束,借助chatGPT神力完成这个项目,希望不要烂尾。

哦,点击本文标题,或者这里,查看第八章全文。 对了,这个项目在gitHub上。如果你发现有可改进之处,欢迎改进并提交PR。

.NET Core/6: Prevent .NET runtime from logging errors that are already handled in ExceptionFilter

We use Graylog to log everything, on Windows machines we also log into EventLog. I recently noticed for every exception I got two items in EventViewer, one is Logged by our code, and the other is logged by the .net runtime I guess. It is a little bit annoying. TLDR; here's the answer:

        public override void OnException(ExceptionContext actionExecutedContext)
        {
            _logger.Error(actionExecutedContext.Exception);
            actionExecutedContext.ExceptionHandled = true;
            actionExecutedContext.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
            actionExecutedContext.Result = new ObjectResult(new ErrorResponse()
            {
                StatusCode = (HttpStatusCode) StatusCodes.Status500InternalServerError,
                Message = actionExecutedContext.Exception.Message,
            });
            base.OnException(actionExecutedContext);
        }

The key is this line actionExecutedContext.ExceptionHandled = true;. Reference