-2

All,

I am using Unit test framework to write my tests in .net. I wrote some unit tests that all access a configuration object (via AppConfig.Current) that is internally a class static.

In the startup I initialize this configuration object and use it immediately in the following line like this:

[AssemblyInitialize]
    public static void AssemblyInitialize(TestContext context)
    {
        var appCfg = AppConfig.Current;
        string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "conf/app.settings.xml");
        appCfg.Load(path);
        var _ = AccountingContext.Current; // <= AccountingContext references the configuration object via "AppConfig.Current" to read some configuration values and initialize the accounting context but I receive a different instance (ONLY in release mode) ....
    }

After loading configuration, next line uses this configuration object (AccountingContext.Current) to initialize itself from the configuration object. The issue is, the tests run fine in Debug mode but in Release mode when I reference the configuration object I get a different object (I know this for a fact because the configuration is not loaded).

So what is the deal with using static reference in unit tests in release mode???

UPDATE: SELF ANSWERED

The issued lied in the "AccountingContext" class. This class is also a static and it initialized itself like this:

 public static AccountingContext Current { get; set; } = new AccountingContext();
public AccountingContext()
        {
            CompanyAccessContext = _CreateCompanyAccessContext();
        }

Changing this intialization to using a static ctor resolved this issue and now everything works:

 public static AccountingContext Current { get; set; } 

        static AccountingContext()
        {
            Current = new AccountingContext();
        }

public AccountingContext()
        {
            CompanyAccessContext = _CreateCompanyAccessContext();
        }

Looks like optimizations were made which changed the actual flow of initialization of AccountingContext. That's a bit unwanted, not sure if this is what everyone expects.

I also found this good resource: Static member variable not being initialized in Release - Compiler/clr bug?

ActiveX
  • 1,064
  • 1
  • 17
  • 37
  • 1
    Define `different object`. Please share a [mcve]. – mjwills Aug 19 '21 at 22:46
  • Found the cause: See my updated comments: Start reading from Update: – ActiveX Aug 19 '21 at 22:56
  • AppConfig.Current - was not giving me the initialized instance, instead that line (used in AccountingContext class) gave me an uninitialized instance. – ActiveX Aug 19 '21 at 23:05
  • 2
    Move that update to a self answer. – Nkosi Aug 19 '21 at 23:09
  • 2
    There is no question in this post. Consider either moving to some other site/blog or maybe as @Nkosi said convert into real Q&A. – Alexei Levenkov Aug 19 '21 at 23:49
  • @AlexeiLevenkov You clearly did not read my post, neither understand the point of update. Here was the question again:So what is the deal with using static reference in unit tests in release mode??? – ActiveX Aug 20 '21 at 01:14
  • 3
    @ActiveX **"What's the deal?" is not a real question** - it's a vague and unhelpful colloquialism - which additionally is only readily understood by certain cultures - for the benefit of users outside of the Anglosphere please edit your post to be more specific. – Dai Aug 20 '21 at 01:18
  • 2
    Also, I think you misunderstand what unit-tests are actually for. **Unit tests should not depend on any external resources or systemwide state**. You're breaking the main rule of unit-tests by loading content from-disk (`appCfg.Load(path);`). You should refactor this into a proper _integration-test_. – Dai Aug 20 '21 at 01:20
  • 2
    Post an answer below and accept it. That's the only right way to "self answered" – Lex Li Aug 20 '21 at 01:21
  • @Dai Plenty of frameworks that use config-based properties allow loading properties from disk for tests (at least, Java and Python ones). – OneCricketeer Aug 20 '21 at 01:42
  • @OneCricketeer What you're describing is better-described as a _text fixture_ - and that should happen _outside_ the unit-test itself. In the OP's case they've got IO code directly in the test, which is not where it should go in that case. – Dai Aug 20 '21 at 01:44
  • @OneCricketeer I'll eat my words. I just saw that the OP's `appCfg.Load(path);` code is indeed in an initialization method and _not_ in the test itself. I was wrong. – Dai Aug 20 '21 at 01:45
  • 1
    However I do maintain that **the OP's software project is badly architectured and needs refactoring** - it's important to avoid mutable `static` state wherever possible. – Dai Aug 20 '21 at 01:46
  • @Dai I don't think sharing configuration for ALL unit tests in a static is a bad thing, please prove me wrong, and if you do make comments on this, you should at least provide alternative solution. ... and who said it was mutable, the configuration is read-only? – ActiveX Aug 24 '21 at 18:07

1 Answers1

-1

Cause of this issue was not using static ctor which guarantees order of initialization. For more details, see updated comments above.

ActiveX
  • 1,064
  • 1
  • 17
  • 37