@@alexisfibonacci Lots of people think MSTest is still v1, and not the replacement V2 from nearly a decade ago. Doesn't help when prominent community members preach against it for no reason, either.
Please make a video on MSTest, explaining the pros and cons please. I'm using MSTest, because I feel it is all we need right now. Many thanks Nick, great content as always :)
I used NUnit for many years and it served me well. Now, in my current team we switched to xUnit because "it's the unofficial successor of NUnit". The more C#-native syntax is nice and for unit tests it's very handy. Syntax, Async and Shared State... But when you want more than simple unit testing, then it's not so "clean" anymore. If you need async initialization you have a problem, as C# does not support async constructors. So you need IAsyncLifetime (more in a second). If you need async disposal, you would think you can use the C#-native IAsyncDisposable - no, not supported, use IAsyncLifetime, but then you also must implement a InitializeAsync() that you may not need (it's the same the other way round). (An interesting future issue may be that IAsyncLifetime has Task DisposeAsync(), while IAsyncDisposable has ValueTask DisposeAsync()) If you want to setup code that runs before all (or a set) of test classes (eg. shared infrastructure setup), then extra classes, attributes and magic strings are required (keyword: "Collection Fixtures"). So the (for me) primary selling point - lean, C#-native-syntax - quickly comes to its limits and falls back requiring some framework-specific (and not so obvious) procedures to get around that, which are sometimes solved "nicer" elsewhere, IMHO. Leaving Unit Test Territory: Integration Tests One thing, that got me by surprise was that xUnit does not play well with integration tests + limiting parallelism. This was/is discussed in this issue: github.com/xunit/xunit/issues/2003#issuecomment-1426388783 . This issue was closed because "it works as designed" and "xUnit is designed for [real] unit tests" (paraphrased). An DDoS-ed test infrastructure causing random timed out tests may be the result. This I wished I would have known earlier, because I don't want to use more than 1 test framework in a solution - I want one that can handle all kinds of tests and has me officially covered. Visual Studio specific Issues When using slow starting xUnit Collection Fixtures, the test explorer does not count the Collection Fixture startup in the test duration. For example, if an integration test starts up a infrastructure Docker Image (TestContainers), this takes about 10s, but the explorer only shows 0.5s after the run because the actual test method only took 0.5s. This is misleading. Also, the current xUnit Visual Studio (2022) test adapter does not fully support inherited tests (testing 2+ implementations with 1 set of tests to ensure all implementations behave the same). Those tests work and the Test Explorer UI shows them correctly - but double clicking on such a test doesn't open anything (it should open the test-source), which is annoying. Conclusion In new projects I will use NUnit again, because in my experience ... it just works, has good documentation and is well integrated in Visual Studio and the like. PS: Instead of the built-in assertions, in the (many) last years I only ever really used FluentAssertions which is just a joy for writing assertions. And it works for many test frameworks, including xUnit and NUnit.
NUnit, simply because I can hammer units tests out in minutes, whereas XUnit always takes a bit of boiler-plating to get going and doesn't have the best mock injection workflow with it creating a new instance of a class on each test. Ideal for some scenarios but not the ones I employ. My ideal combo: NUnit + Moq + Bogus + AutoBogus Hooks into EFCore nicely via in-memory DB package; I personally prefer a full-fledged ORM versus a wrapper/helper like Dapper; but I'm sure given the flexibility of Dapper unit tests wouldn't be very difficult to setup with extension packages like Moq.Dapper.
Hi Nick. In NUnit you usually would initialize SUT in SetUp method. Then you will get a separate instance per test and TestContext.Out.WriteLine will print different GUIDs.
He's just successfully convinced me to avoid xUnit😊 Why would I want to create a fixture object for each test to slow it down? The sole purpose of the fixture class is to share common data to reduce setup time. One can use the [Setup] method to change the per-test data.
@@antonmartyniuk thousends of kilometers ahead in what? I was forced to migrate to xunit from nunit for over two years now and sitll looking back sometimes...
Good reminder video of why I used xunit for that many years. Together with Fluent Assertions for asserting, NSubstitute for mocking and AutoData for injecting mocks and data I’m happy writing tests.
4:35 Let me disagree with you on this statement. I consider that initializing fields and using a constructor in a test class is more natural in NUnit because it initializes fields and uses these instances in all test methods as it goes in a usual C# class. And yes, if we need to use a unique instance in each method, we can use the Setup attribute for this. PS: Assertions in NUnit are more pleasant to use and we can avoid using the FluenAssertion library.
in XUnit also possible to share the context between test classes when writing integration tests that require running containers. In NUnit, you have to recreate the context completely or use dirty hacks to pass it through static classes
I used MSTest for years, never had a problem with it. Admittedly I would use xUnit on a new project today since I like the feature set better, but there is no return on investment for me to convert all my old tests away from MSTest, it works just fine and it's well supported by Microsoft.
0:32 "Everyone knows you should not be using MSTest though... like, come on... use something else..." Care to elaborate on that a bit? I've never personally felt it was a problem, and noone on teams I've worked with have raised it as an issue, or suggested we switch to NUnit or xUnit. I've been working on several large corporate c# projects for the last 5 years, predominately unit tests were MSTest only.
As QA engineer I prefer NUnit. 1. It gives you access to test context i.e. metadata about test (currently executing test class, method etc.), possibility to attach some files (like screenshots, files with logs etc.). 2. It's more flexible in parallel tests execution - xUnit is not able to run tests cases inside class in parallel. 3. Data driven tests are more intuitive and flexible in NUnit - it allows to combine them and generate tests automatically. 4. NUnit has possibility to mark test as inconclusive. 5. NUnit has possibility to order tests. Agree, that maybe in unit tests these features may be not needed, but in integration or E2E tests they are very useful.
I completely agree. I have written thousands of tests for Nunit and find it much more powerful. Comparing two frameworks by how they run is not correct. There was no comparison of writing parameterized tests, the advantage of the Values attribute was not shown, the possibilities of Assert.That (pooling, waiting for the result and other constraints) were not shown. Tests in the real world are much more complicated than comparing two strings, especially when writing tests for legacy code.
Btw. NUnit also had a similar interface for tests as XUnit with something like Assert.AreEqual(), but there is this newer fluent API using Assert.That(). I started using FluentAssertions for that. Technically, it is fully redundant, but you can use it with any of these frameworks and you get the same assertions.
I use NUnit mainly because thats what we use at work. However i feel like its actually the best option from this description aswell. Having the classes be singletons makes a lot more sense to me. That way its also cleaner to read what variables are useable for that specific test and what variables are not available. Also if you have some sort of global test setup logic like creating a file, downloading a file etc. Im not sure how you would do that using xunit without having to do said logic multiple times over.
Originally we were using MSTest because it is integrated and didn't need any extensions in visual studio. Today we are still using MSTest because of the mentioned historical reasons, but to be honest, I am not missing anything with MSTest, especially since 3.0. The one instance per class sounds great though, right now I am doing it manually by having a context instance that is created in every test.
I just use the [TestInitalize] for each class, I think MSTest uses the best attribute names like [TestClass] [TestMethod] etc. But I also like that XUnit doesn't need them, I don't know if the class is created for each test in MSTest, it hasn't been a problem
I think it only creates the class once, because it also has a [ClassInitialize] attribute. So the stuff Nick talks about with shared elements across tests would naturally be handled in the [ClassInitialize], while stuff that needs to be changed for each test would be in [TestInitialize]. I prefer it to xUnit's approach because it's clear exactly what's happening, rather than needing magic generic templates or whatever.
@@David-id6jwyeah, but ClassInitialize (AFAIR) is "decorable" only on static methods. I'm almost sure MSTest is instancing test classes the same way as xUnit.
@@David-id6jw MSTest uses a new instance for each test. They just added the Testinitialize method so the purpose is more clear, but you can just skip it and use the contstructor for that, that's what I often do, as I can use readonly fields than.
I'm using MsTest because it was built-in. Regarding the class initialisation it's like xUnit (new instance of every test). I have over 3000 tests so I need a VERY good reason to re-write those! What's wrong with MsTest?
I've never got any clear response to that question. I suppose that it is the usual unreasonable "Microsoft" bashing that has made people hate MS Test. There could have been a chance where earlier versions of MS Test lacked features that NUnit provided at that time. But there is no compelling reason today to rewrite my tests to NUnit or XUnit. MS Test never really gets in the way between you and your tests. I like it that way.
IMO, a new instance of the test fixture class per method tested is not only a waste of system resources, (especially when you have a large number of tests) but when you’re testing something like HttpClient operations (where you want to persist the client from the IHttpClientFactory), statics, or singletons, you’re going to get undesired results, no?
The reason behind Assert.Pass not being in xunit can possibly be attributed to bad unit tests. There's nothing stopping you from doing an empty try-catch to avoid that exception in xUnit. In QA, if you reach the end of the test and all assertions have passed, the test is a pass.
MSTest! Originally mostly because it was developed by MS. Then I quickly started enjoying its simplicity and how easy it is to have up and running (dotnet new mstest && dotnet test, that’s it!) (I guess other frameworks are easier to run nowadays with the dotnet CLI too). And still using it because… there isn’t a day where I feel I’m missing something. No frictions. It’s better than good enough: it just never gets in my way, and does what it says it does. A tool that weighs like a feather. Never makes me think about testing frameworks, and so I never think about switching.
I just use MSTest so far. What you showed with xUnit I achieve by writing a nested class that I instantiate at the start of every test. it's usually disposable and it will have the SUT and any mock dependencies created with options for setting known values and so on. what you did with xUnit is slightly cleaner by basically using the test class itself as the SUT wrapper.
I assume that in Nick's case, he wanted the test to pass whether it throws an exception or not, ie: two possible positive outcomes. In that case, Assert.Throws would not work. But he could just add a try / catch for that exception, and do nothing or end the test in the catch.
First of all, love your videos! :) I disagree with your "instantiating the test class for every test is better" argument, cause I would expect a property in my test class to be the same when instantiating it inline and not changing it afterwards. Also you can mark it as readonly (as you do) if its not supposed to be changed by your tests (generally I would avoid global variables to be changed in methods - so for me it allows for a bad pattern, and NUnit will force you to do it right). Also, I like the [Setup], [Teardown], and also [OneTimeSetUp] and [OneTimeTearDown] attributes that exists in NUnit, as to me, it's more explicit than implementing IDisposeable, and using IClassFixture. I clicked on the video to kind of get the "this is why you should pick XUnit in this scenario or this is why you should pick NUnit in that scenario" - instead I got "They can do pretty much the same things in different ways, but XUnit is more popular". I value your points and video though :D I'll keep searching for someone to change my mind about NUnit versus XUnit :) But it also seems there's a good reason both exists, which annoys me a bit :D
I start new projects with Nunit. I've never felt that I've been missing something in my test framework. I have hit the issue with state being persistent across tests only 2 weeks ago, but it wasn't that much work to work around. There might be something to be said for in that tests can get quite long, which is definitely true for our Integration tests, but even then it's not too much of an issue.
Thank you for this video. Everything was new to me. I'm used to using NUnit and am familar with the syntax. However xUnit is also very straight forward.
Do you use any assertion libraries? I've become pretty fond of Fluent Assertions (along with Fluent Validations), but learned about Shoudly today which looks neat but doesn't seem to be as feature rich or as popular as Fluent Assertions. Would love to see a video on these kinds of libraries.
If you want to have separate instances of a class in NUnit, would you not simply create the object inside the test method, instead of a class variable? Class variables are supposed to be reused among all methods.
I have a problem with xUnit, it is missing some features that exist in NUnit. It doesn't support generic TestFixture. Also, it doesn't have retry/replay attributes (but some nugets add this functionality).
Thank you for the video comparison, I've been interested in a short description of the differences between these two testing frameworks (all other videos that I found were very long and included a lot of fillers that are perfect for new learners but not great if you are only interested to know the difference between them). I really prefer the NUnit syntax, I think it's more readable. And NUnit has persistence in the entire TestFixture, which I prefer (same as describe in Jest/Vitest). I usually put the Repeat decorator for a test/suite to check that it's persistent and not flaky.
Which is the best way approach on sending a list of test case objects (usually values and expected values, but with the flexibility to design the TestCase class with what ever properties you like) in xUnit? I have used this in NUnit with [TestCaseSource(typeof(TestCases), nameof(TestCases.TestCasesCollection))] and found it to be nice to make a clear representation of what a TestCase is in the given context as well as separating the test data from the actual test and its logic. Great video/content as always and keep up the good work!
I would very much like it if you would talk about the strength and weaknesses when it comes to MSTest and xUnit. I personally love xUnit over anything else when it comes to unit testing, but I recently joined a team that want to stay with MSTest because "that is what we have been doing for a long time now". I suggested we at least would allow for new unit tests to be written in xUnit, but I was dismissed with the argument of "MSTest has more features available". I know MSTest has more annotation commands, but I believe xUnit has a better isolation strategy - however I was not convincing enough. Can your future video on MSTest help me with that?
Nick, in the “complex” example you showed some shared context and seems like you are using ICollectionFixture for it. We are doing exactly the same but we faced a terrible consequence we don't have a workaround for: tests in the same collection can't be executed in parallel. Did you manage to fix it somehow? I think about switching to NUnit because of it.
I use xUnit for exactly that it creates one instance of the test class for each test execution (even for theories). If a system gets a large set of devs banging out stuff it less likely to break due a lack of understanding of instance state. Otherwise all the three main test frameworks are much of a much-ness, but this one behavior of xUnit is the "killer app" that makes it the choice.
Glad to see this video, at least the reason is not following what internal dotnet team uses blindly. I have been using xUnit 2 years, previously I used NUnit more than 6 years. The only reason I uses xUnit is because my team/tech lead wants it. I never use xUnit without FluentAssertion. xUnit's assertion is poor compared to NUnit. One of missing feature in xUnit from NUnit is test session fixture setup. xUnit only allows per test/class level setup. I used it before in NUnit and don't see feature equivalent in xUnit. One of the best feature from FluentAssertion is object graph comparison. I use it a lot in my test projects, it's very flexible and powerful. So my best combination will be NUnit+FluentAssertion. NUnit covers most of the case in my project (assertion helper, setup). I like the new style which is more BDD. It's very flexible, either for single object testing or collection testing. I will use FluentAssertion for object graph testing only. Previously, I have to write my own implementation just to implement this in NUnit.
It's been a while since I'd moved to xUnit, as that's what the new team had + I wanted to check the hype around it, but I still find nUnit to be more CONSISTENT and CLEAR. You can change from per test to per run setup by simply replacing an annotation and when reading existing code it's very clear what it's going to do without looking into docs. Also nUnit works better with multiple sets of data as you can specify what RETURN RESULT you expect, instead of introducing additional 'expectedValue' input -> much cleaner. Plus no nonsense [fact]/[theory] distinction. Also if you want to use original Asserts I find nUnit ones better and more obvious, plus they support '.That' pattern which is nice. On top of that we've experienced multiple deadlock problems with xUnit, that were terrible to debug, and the author's response to issues in the framework that were pointed out in github wasn't exactly building confidence.
no. you don't need TestFixture unless you have some setup to put in it. TestCase working fine themselves. The one time init showcase is not representative at all, as we have SetUp for it. NUnit is sequential execution by default, so SetUp works pretty solid for, you guessed it, test run setup. And NUnit being translation of JUnit - we can say it was not designed from scratch in the first place. On the contrary, xUnit was created from scratch when guys realized testing in C# missing a lot with NUnit (say Java) way and it's worth to give C# it's own clean test way. And we don't want to mess with long time living NUnit and make some non-compatible changes - so they decided to create a new testing lib. And they did it the right way so each run is from scratch and test class also from scratch - so your setup not is a constructor - we're good to run all of these in parallel in the most cases. Not sure it's fair to day NUnit tests are flaky. You need to know tools you're working with. For NUnit you know it's not going to create new test class for every test run. For xUnit - you know it will.
xUnit is missing some key features. For example, there's no way in xUnit to perform setup prior to all tests. There are some third party libraries that fill in the gaps, but they don't work seamlessly with things like IMessageSink. xUnit also has no way to run arbitrary code after test failure. This can be incredibly useful when unit testing things like MassTransit consumers where you might want to output the message timeline on test failure.
I only use xUnit nowadays, basically because of the reasons they wrote in the "Why Did we Build xUnit 1.0?" documentation article. But let me name the most important things: better isolation, by default parallel, more natural constructs (as you mentioned too, C# constructs instead of attributes only). And yeah, maybe you need to make a video on why MSTest is/was garbage.
Oh yes, when using NUnit after xUnit it's confusing that you need to TearDown class objects so that tests don't clash (usually need to reset mocks in NUnit) I have used both a lot and to me they are equally good. Here are my thoughts: NUnit: - I prefer reading [Test], [TestCase()] over [Fact], [Theory] - [InlineData()], makes more sense to me. - It kind a forces you to think about isolating tests better so that they don't clash - should you really reuse the code or use the same class objects? Tests should be dumb and test only what's needed and not care about other tests. xUnit: - Default behavior that the class is initialized for each test does make it easier to not think about clashing tests, however this can lead to coupled tests, where you could start initializing common test objects in constructor and then tests can grow, when something changes only for few tests. - Less code if default behavior is exactly what you need and if you are aware of it And for all Asserts I like to use global.usings -> FluentAssertions, so doesn't matter which framework is used
the arguments are pretty "random". As said in the intro: a matter of taste. Both are available, both have are large community. Essentially you can't go wrong. It is more important to provide good documentation how to solve common testing issues, e.g. how to genrate read-world data to test DB performance read AND write operations. also: how to add failure to in certain layers (with a random chance of occurance) etc. Most tests, acutally test only that a) the compiler works, b) that the specification - which changes all the time - is being fulfilled.
May I ask your thoughts on using var versus explicit data types? Example: "Guid id = ..." vs "var id = ..." I recently made the switch to using Rider from VS, and I find it odd how Rider always throws warning when I try and use the explicit version, and it recommends I change them all to var.
I’m late here but that’s merely Rider/ReSharper’s default code style. I’ve altered my own so that it doesn’t complain if I use the explicit type. You don’t gain anything from either, it’s down to preference and/or convention.
I've used xUnit and MSTest. I tend to like MSTest because it is there out of the box. I've never been very impressed by the It.ShouldNotBe(x); syntax. It is fine, but I wouldn't install a library just for that. I'd like to know what drives the scoffing about MSTest. I really haven't seen a huge benefit to the other frameworks. Mostly, I'm just happy if people are writing tests and treat them as a meaningful part of the application.
The reasoning of "using knowledge you know in c#" can be debatable. In most cases when I have a class of methods. I usually would instantiate a single object and call their methods. I wouldn't be instatiating a class for each method I want to call. Both xUnit and nUnit has its nuances. With nUnit you can think that each class is instantiated once. But how would you achieve separate context? That's why you have a setup and teardown. Other test framework in other languages do that as well. I understand this is just his preference but I think a more reflective comparison is fairer.
Doesn't really matter tbf As long as the unit is being tested fully just use which ever framework is currently in use on the code base you're working on. I also find that running the class through GPT and asking it to provide a skeleton test suite covering all positives, negatives and edge cases makes Unit testing a whole lot faster. If I'm working on my own projects though it's definitely XUnit :)
In VS Code, the xUnit ITestOutputHelper does NOT write anything out unless I failed test. This "feature" is VERY annoying and make me think switch back to NUnit.
xUnit it is, then, Nick. You say I should do what I like, but so far, following your advices didn't get me bad results, so I will just keep using the "what would Nivk Chapsas do" design pattern 😄
I wasted so much time on XUnit. It was so painful when I tried to use it in integration tests with a db and web api test fixture and varying configurations. You have to make your own plugins and such to parameterize your tests. Parameterization is built in to nunit and is easy to use. So I ended up using XUnit for unit tests and nunit for integration tests which is not ideal.
I started using NUnit very long time ago even before MSTest was available. A couple of years ago I switched to XUnit. I have never used MSTest regularly, but it looks like polished NUnit for me. From my point of view there are 2 bad things about XUnit: missing documentation and that it is relatively slow (in comparison with others). On the other hand, you can easily run tests in parallel using XUnit, so it is better scalable.
For simple unit tests I do not care. But NUnit is my option for intergration tests. For exeample when you want to isolate tests with transaction scope to keep database state pristine for other test scenarios, in xunit ClassFixture is initialized on a separate async context thus that scope does not carry over to facts (no, async option on transaction scope is not a solution here). also tests ordering or some global inits are harder in xuinit, require custom code. With NUnit all those issues do not exist.
I share similar feelings about NUnit and xUnit, about Assert.Pass(): I don't think there is anything wrong to just say Assert.Equal(true, true), but I go for FluentAssertions usually anyway.
@@LukeGeorgalas yeah, sometimes you miss obvious ones, right? Although, Assert is still more descriptive, you see Assert and you know it's to do with testing and it is on purpose.
NUnit using the same instance for all Tests in the class hit me hard when working with Unity3D... Also the version used was so old, it didn't support the "instance per test" behavior at all.
Me, who is just getting started with test driven development, completely enchanted by what MSTest can do, and I immediately get to hear its apparently trash :D
Interesting take on why you use xUnit over nUnit. And personally I agree that xUnit makes more sense in several parts of it's implementation. I just think one of your arguments is kind of a bit flawed. You like xUnit more because it takes C# concepts to represent testing concepts. But on the other hand you also like xUnit that it treats test methods as unrelated to the other test methods in the same class. Isn't it a C#/OOP concept to group related things in the same class? And those related things share the same state that you define. So from this arguments perspective you should like nUnit more since it uses the correct C#/OOP concept. But you don't because some devs tend to not be good with these concepts.
When C# added nullable reference types, xUnit became the clear winner. If you want to do the normal thing and reinstantiate your SUT in each test, then in xUnit, you can declare a field and assign it either at the field declaration, or in the constructor, and that's it. Whereas in NUnit, if you write the equivalent code (assigning the field in your `[SetUp]`), then you get a compiler warning that your SUT field is declared as non-nullable but isn't initialized in the constructor. You have to declare your SUT field as nullable, or use `#nullable disable` on your test class, or not have a field at all and just duplicate the instantiation in each test, or some other unpleasant workaround. With xUnit, it Just Works.
Exactly, xUnit works much better with nullable reference types. I was also creating sut's and mocks in the SetUp method, I was surprised that Nick is doing it in ctor.
Except that as soon as you need asynchronous setup and teardown methods you'll have to resort to `IAsyncLifeTime` which suffers from the exact same downside.
If you install NUnit.Analyzers, it will recognise the pattern of initialising the field in [SetUp] and automatically disable the warning for you (in addition to many other helpful analysers) so you can declare the field as non-nullable without issue.
I favor NUnit every time because xUnit docs are abysmal. I've wanted to start using xUnit for new projects but every time I can't because there are literally zero docs about basic functionality like dynamic input for theories. To find anything about xUnit you have to read probably outdated 3rd party articles which is wild.
Lol I literally program around the class initialization problem in nunit all the time. I just add a initialization method on the test initialization attribute, it’s fine.
A Side note is that not only is the test case operated on a single class in NUnit, it's operated on that class in PARALLEL by default, which is a recipe for disaster. I would add for the people who don't have the option of switching to XUnit you can achieve the separate class per test functionality in NUnit with some annotations on the class with tests in it. [TestFixture] [Parallelizable(ParallelScope.All)] [FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
MSTest is so much better. It creates an instance per test, just like XUnit. It can easily do method level parallelization, which is something XUnit can't do. A lot of the async support is more straightforward.
For Assert.Pass in xUnit, can't you just return? The test will be success if no asserts fail, so by returning it would be success. Assert.Pass shows intent better though.
It's not as simple. Assert.Pass will work from any method or nesting level. return needs to be specially handled to be top level in xunit. It's possible, but you have to compromise with how you write the test
Either you haven’t worked with NUnit or you don’t know, but in NUnit you can configure the creation of objects and destruction (cleaning) for each test or group of tests. Why the hell mislead people?
Same. 😅 Until now... now we have no unit tests. I'm about to create the first ones, so here I am. 🤣 I'm leaning towards NUnit, though it could be I'm just more used to the syntax, even with all the inconveniences...
I feel like everything discussed here is about features of the test runners that are intended to make writing tests that have complicated setup and finalize easier. However, I am strongly in the camp of, if your tests are hard to write, you have done something wrong. For one, it means you wrote the code first, which is a big no-no in TTD. Second, it tells you that you didn't write testable code which you wouldn't have done had you written the tests first. Write your tests first, and your tests become so simple that you don't need to worry about these extra features of the test runner. The fix is not to use the complex pieces of the test runner. The fix is to refactor the code to be testable.
I like the default of xUnit as well. But NUnit has a FixtureLifeCycle attribute. With LifeCycle.InstancePerTestCase you can ensure your classes will be instantiated the same way as in xUnit, with the constructor and IDisposable. You can also mark your assembly to use this for all the classes. Very handy when running test in full parallel, because SetUp is not 100% safe.
Im still using nunit because of only one frature - testing internal classes and interfaces without exposing them. For those who saying you should test only public things, I dont agree
@@tunawithmayo Perfectly normal to have internals that you unit test when creating a library. If its in application code then its very questionable. That said, I use xUnit for this and just `InternalsVisibleTo` the test assembly.
@@Denominus Well, that doesnt work if you have some kind of component test wrapper where you put tested interface in generic base class. That setup requires you to have internal test class (because you cannot have public class and inheriting from internal, even in generic argument). Unfortunatelly xunit cannot handle it. Nunit works perfectly well with testfixture attribute
I came to the video looking for why you'd be using NUnit not xUnit 😁 A lot of people use xUnit because it's getting Microsoft's 1st class support (in docs and examples, etc.) since the creator joined the company.
I use NUnit because I'm an old fart and I haven't found a need to switch to xUnit yet. But I'd be happy to use xUnit if I'm put on a project that already uses it.
Ok looks like I need to make a video on MSTest
Why you shading MSTest?
@@alexisfibonacci Lots of people think MSTest is still v1, and not the replacement V2 from nearly a decade ago. Doesn't help when prominent community members preach against it for no reason, either.
@@toddosty I never heard it mentioned in a negative light until I watched this.. I thought all 3 were identical TBH. They.. run your tests..
Please make a video on MSTest, explaining the pros and cons please. I'm using MSTest, because I feel it is all we need right now. Many thanks Nick, great content as always :)
Yeah I also shaking to know what's the problem with MS test?! That's my default when it comes to test
I used NUnit for many years and it served me well. Now, in my current team we switched to xUnit because "it's the unofficial successor of NUnit". The more C#-native syntax is nice and for unit tests it's very handy.
Syntax, Async and Shared State...
But when you want more than simple unit testing, then it's not so "clean" anymore.
If you need async initialization you have a problem, as C# does not support async constructors. So you need IAsyncLifetime (more in a second).
If you need async disposal, you would think you can use the C#-native IAsyncDisposable - no, not supported, use IAsyncLifetime, but then you also must implement a InitializeAsync() that you may not need (it's the same the other way round).
(An interesting future issue may be that IAsyncLifetime has Task DisposeAsync(), while IAsyncDisposable has ValueTask DisposeAsync())
If you want to setup code that runs before all (or a set) of test classes (eg. shared infrastructure setup), then extra classes, attributes and magic strings are required (keyword: "Collection Fixtures").
So the (for me) primary selling point - lean, C#-native-syntax - quickly comes to its limits and falls back requiring some framework-specific (and not so obvious) procedures to get around that, which are sometimes solved "nicer" elsewhere, IMHO.
Leaving Unit Test Territory: Integration Tests
One thing, that got me by surprise was that xUnit does not play well with integration tests + limiting parallelism. This was/is discussed in this issue: github.com/xunit/xunit/issues/2003#issuecomment-1426388783 . This issue was closed because "it works as designed" and "xUnit is designed for [real] unit tests" (paraphrased). An DDoS-ed test infrastructure causing random timed out tests may be the result.
This I wished I would have known earlier, because I don't want to use more than 1 test framework in a solution - I want one that can handle all kinds of tests and has me officially covered.
Visual Studio specific Issues
When using slow starting xUnit Collection Fixtures, the test explorer does not count the Collection Fixture startup in the test duration. For example, if an integration test starts up a infrastructure Docker Image (TestContainers), this takes about 10s, but the explorer only shows 0.5s after the run because the actual test method only took 0.5s. This is misleading.
Also, the current xUnit Visual Studio (2022) test adapter does not fully support inherited tests (testing 2+ implementations with 1 set of tests to ensure all implementations behave the same). Those tests work and the Test Explorer UI shows them correctly - but double clicking on such a test doesn't open anything (it should open the test-source), which is annoying.
Conclusion
In new projects I will use NUnit again, because in my experience ... it just works, has good documentation and is well integrated in Visual Studio and the like.
PS: Instead of the built-in assertions, in the (many) last years I only ever really used FluentAssertions which is just a joy for writing assertions. And it works for many test frameworks, including xUnit and NUnit.
Thank you for the elaborated overview and knowledge sharing, almost as much value as the video itself.
This comment needs more likes :)
This is a great analysis. NUnit ftw.
Do you know if FluentAssertions will go .net8 or not? Ok, it works in the project, but it looks weird to me that the package is .net6.
Wait, you guys have Unit Tests?!
NUnit, simply because I can hammer units tests out in minutes, whereas XUnit always takes a bit of boiler-plating to get going and doesn't have the best mock injection workflow with it creating a new instance of a class on each test. Ideal for some scenarios but not the ones I employ.
My ideal combo: NUnit + Moq + Bogus + AutoBogus
Hooks into EFCore nicely via in-memory DB package; I personally prefer a full-fledged ORM versus a wrapper/helper like Dapper; but I'm sure given the flexibility of Dapper unit tests wouldn't be very difficult to setup with extension packages like Moq.Dapper.
The current iteration of MSTest is not that bad; it looks and feels very much like NUnit.
MSTests all the way!
I use MSTest it's easy to get started with
Me using MsTest and making it past 0:33 T_T
Hi Nick. In NUnit you usually would initialize SUT in SetUp method. Then you will get a separate instance per test and TestContext.Out.WriteLine will print different GUIDs.
He showed that and explained why that's not the point.
He's just successfully convinced me to avoid xUnit😊 Why would I want to create a fixture object for each test to slow it down? The sole purpose of the fixture class is to share common data to reduce setup time. One can use the [Setup] method to change the per-test data.
Great content as usual Nick; you should probably do a video explaining why we should not use MSTest
Yep! For most cases it's now splitting hairs, at least from a pragmatic standpoint.
MsTest just evolved to NUnit, while xUnit is thousands of kilometres ahead. MsTest is a almost like an Internet Explorer, lol
@@antonmartyniukWhy?
@@antonmartyniuk thousends of kilometers ahead in what? I was forced to migrate to xunit from nunit for over two years now and sitll looking back sometimes...
What's wrong with MSTest? I'm having basically the same experience as in nunit/xunit?
Good reminder video of why I used xunit for that many years.
Together with Fluent Assertions for asserting, NSubstitute for mocking and AutoData for injecting mocks and data I’m happy writing tests.
4:35 Let me disagree with you on this statement.
I consider that initializing fields and using a constructor in a test class is more natural in NUnit because it initializes fields and uses these instances in all test methods as it goes in a usual C# class.
And yes, if we need to use a unique instance in each method, we can use the Setup attribute for this.
PS: Assertions in NUnit are more pleasant to use and we can avoid using the FluenAssertion library.
in XUnit also possible to share the context between test classes when writing integration tests that require running containers. In NUnit, you have to recreate the context completely or use dirty hacks to pass it through static classes
I used MSTest for years, never had a problem with it. Admittedly I would use xUnit on a new project today since I like the feature set better, but there is no return on investment for me to convert all my old tests away from MSTest, it works just fine and it's well supported by Microsoft.
0:32 "Everyone knows you should not be using MSTest though... like, come on... use something else..."
Care to elaborate on that a bit?
I've never personally felt it was a problem, and noone on teams I've worked with have raised it as an issue, or suggested we switch to NUnit or xUnit.
I've been working on several large corporate c# projects for the last 5 years, predominately unit tests were MSTest only.
As QA engineer I prefer NUnit. 1. It gives you access to test context i.e. metadata about test (currently executing test class, method etc.), possibility to attach some files (like screenshots, files with logs etc.). 2. It's more flexible in parallel tests execution - xUnit is not able to run tests cases inside class in parallel. 3. Data driven tests are more intuitive and flexible in NUnit - it allows to combine them and generate tests automatically. 4. NUnit has possibility to mark test as inconclusive. 5. NUnit has possibility to order tests. Agree, that maybe in unit tests these features may be not needed, but in integration or E2E tests they are very useful.
I completely agree. I have written thousands of tests for Nunit and find it much more powerful. Comparing two frameworks by how they run is not correct. There was no comparison of writing parameterized tests, the advantage of the Values attribute was not shown, the possibilities of Assert.That (pooling, waiting for the result and other constraints) were not shown. Tests in the real world are much more complicated than comparing two strings, especially when writing tests for legacy code.
Btw. NUnit also had a similar interface for tests as XUnit with something like Assert.AreEqual(), but there is this newer fluent API using Assert.That(). I started using FluentAssertions for that. Technically, it is fully redundant, but you can use it with any of these frameworks and you get the same assertions.
Assert.AreEqual() This is an old spelling, Assert.That() is better to use
I use NUnit mainly because thats what we use at work. However i feel like its actually the best option from this description aswell. Having the classes be singletons makes a lot more sense to me. That way its also cleaner to read what variables are useable for that specific test and what variables are not available. Also if you have some sort of global test setup logic like creating a file, downloading a file etc. Im not sure how you would do that using xunit without having to do said logic multiple times over.
Originally we were using MSTest because it is integrated and didn't need any extensions in visual studio.
Today we are still using MSTest because of the mentioned historical reasons, but to be honest, I am not missing anything with MSTest, especially since 3.0.
The one instance per class sounds great though, right now I am doing it manually by having a context instance that is created in every test.
IIRC MSTest already creates one intances per test, just like xUnit.
I just use the [TestInitalize] for each class, I think MSTest uses the best attribute names like [TestClass] [TestMethod] etc. But I also like that XUnit doesn't need them, I don't know if the class is created for each test in MSTest, it hasn't been a problem
I think it only creates the class once, because it also has a [ClassInitialize] attribute. So the stuff Nick talks about with shared elements across tests would naturally be handled in the [ClassInitialize], while stuff that needs to be changed for each test would be in [TestInitialize]. I prefer it to xUnit's approach because it's clear exactly what's happening, rather than needing magic generic templates or whatever.
@@David-id6jwyeah, but ClassInitialize (AFAIR) is "decorable" only on static methods. I'm almost sure MSTest is instancing test classes the same way as xUnit.
@@David-id6jw MSTest uses a new instance for each test. They just added the Testinitialize method so the purpose is more clear, but you can just skip it and use the contstructor for that, that's what I often do, as I can use readonly fields than.
I'm using MsTest because it was built-in. Regarding the class initialisation it's like xUnit (new instance of every test).
I have over 3000 tests so I need a VERY good reason to re-write those!
What's wrong with MsTest?
I've never got any clear response to that question. I suppose that it is the usual unreasonable "Microsoft" bashing that has made people hate MS Test. There could have been a chance where earlier versions of MS Test lacked features that NUnit provided at that time. But there is no compelling reason today to rewrite my tests to NUnit or XUnit.
MS Test never really gets in the way between you and your tests. I like it that way.
We’re using MSTest and it’s been perfectly good. The DataRow attribute saves a lot of repetition.
10:18 What about "catch(ExpectedException ex) { return; }" to pass a test after excetpion in xUnit?
IMO, a new instance of the test fixture class per method tested is not only a waste of system resources, (especially when you have a large number of tests) but when you’re testing something like HttpClient operations (where you want to persist the client from the IHttpClientFactory), statics, or singletons, you’re going to get undesired results, no?
MSTest2 + Fluent Assertions it's being sufficient to me.
What's wrong with MSTest?
The reason behind Assert.Pass not being in xunit can possibly be attributed to bad unit tests. There's nothing stopping you from doing an empty try-catch to avoid that exception in xUnit.
In QA, if you reach the end of the test and all assertions have passed, the test is a pass.
xUnit has Assert.Throws for expecting exceptions, but nothing that I'm aware of to just "eyyo pass the test it's all good we're Volkswagen" method
MSTest! Originally mostly because it was developed by MS. Then I quickly started enjoying its simplicity and how easy it is to have up and running (dotnet new mstest && dotnet test, that’s it!) (I guess other frameworks are easier to run nowadays with the dotnet CLI too). And still using it because… there isn’t a day where I feel I’m missing something. No frictions. It’s better than good enough: it just never gets in my way, and does what it says it does. A tool that weighs like a feather. Never makes me think about testing frameworks, and so I never think about switching.
I just use MSTest so far. What you showed with xUnit I achieve by writing a nested class that I instantiate at the start of every test. it's usually disposable and it will have the SUT and any mock dependencies created with options for setting known values and so on. what you did with xUnit is slightly cleaner by basically using the test class itself as the SUT wrapper.
I prefer XUnit.
In relation to NUnit's Assert.Pass().
For XUnit when testing and knowing an exception is expected, I've used XUnit's Assert.Throws
I assume that in Nick's case, he wanted the test to pass whether it throws an exception or not, ie: two possible positive outcomes. In that case, Assert.Throws would not work. But he could just add a try / catch for that exception, and do nothing or end the test in the catch.
First of all, love your videos! :)
I disagree with your "instantiating the test class for every test is better" argument, cause I would expect a property in my test class to be the same when instantiating it inline and not changing it afterwards. Also you can mark it as readonly (as you do) if its not supposed to be changed by your tests (generally I would avoid global variables to be changed in methods - so for me it allows for a bad pattern, and NUnit will force you to do it right).
Also, I like the [Setup], [Teardown], and also [OneTimeSetUp] and [OneTimeTearDown] attributes that exists in NUnit, as to me, it's more explicit than implementing IDisposeable, and using IClassFixture.
I clicked on the video to kind of get the "this is why you should pick XUnit in this scenario or this is why you should pick NUnit in that scenario" - instead I got "They can do pretty much the same things in different ways, but XUnit is more popular".
I value your points and video though :D I'll keep searching for someone to change my mind about NUnit versus XUnit :) But it also seems there's a good reason both exists, which annoys me a bit :D
I start new projects with Nunit. I've never felt that I've been missing something in my test framework. I have hit the issue with state being persistent across tests only 2 weeks ago, but it wasn't that much work to work around.
There might be something to be said for in that tests can get quite long, which is definitely true for our Integration tests, but even then it's not too much of an issue.
What's your opinion on Fixie, attribute-free testing framework based on conventions?
Thank you for this video. Everything was new to me.
I'm used to using NUnit and am familar with the syntax. However xUnit is also very straight forward.
Do you use any assertion libraries? I've become pretty fond of Fluent Assertions (along with Fluent Validations), but learned about Shoudly today which looks neat but doesn't seem to be as feature rich or as popular as Fluent Assertions. Would love to see a video on these kinds of libraries.
If you want to have separate instances of a class in NUnit, would you not simply create the object inside the test method, instead of a class variable?
Class variables are supposed to be reused among all methods.
Nunit has attribute LifeCycle.InstancePerTestCase
Which will help you create an instance per each test.
I have a problem with xUnit, it is missing some features that exist in NUnit. It doesn't support generic TestFixture. Also, it doesn't have retry/replay attributes (but some nugets add this functionality).
What's your thoughts about the NUnit contraint model for asserts?
Thank you for the video comparison, I've been interested in a short description of the differences between these two testing frameworks (all other videos that I found were very long and included a lot of fillers that are perfect for new learners but not great if you are only interested to know the difference between them).
I really prefer the NUnit syntax, I think it's more readable. And NUnit has persistence in the entire TestFixture, which I prefer (same as describe in Jest/Vitest). I usually put the Repeat decorator for a test/suite to check that it's persistent and not flaky.
Just one general questions,
will the courses on dometrain also be updated?
Dometrain courses try to stay up to date with LTS .NET versions
@@nickchapsas thanks for answer!
Which is the best way approach on sending a list of test case objects (usually values and expected values, but with the flexibility to design the TestCase class with what ever properties you like) in xUnit? I have used this in NUnit with [TestCaseSource(typeof(TestCases), nameof(TestCases.TestCasesCollection))] and found it to be nice to make a clear representation of what a TestCase is in the given context as well as separating the test data from the actual test and its logic. Great video/content as always and keep up the good work!
I would very much like it if you would talk about the strength and weaknesses when it comes to MSTest and xUnit. I personally love xUnit over anything else when it comes to unit testing, but I recently joined a team that want to stay with MSTest because "that is what we have been doing for a long time now". I suggested we at least would allow for new unit tests to be written in xUnit, but I was dismissed with the argument of "MSTest has more features available". I know MSTest has more annotation commands, but I believe xUnit has a better isolation strategy - however I was not convincing enough.
Can your future video on MSTest help me with that?
MSTest has the same test isolation as xUnit... an instance of the test class is created for each test that is run.
Nick, in the “complex” example you showed some shared context and seems like you are using ICollectionFixture for it. We are doing exactly the same but we faced a terrible consequence we don't have a workaround for: tests in the same collection can't be executed in parallel. Did you manage to fix it somehow? I think about switching to NUnit because of it.
I use xUnit for exactly that it creates one instance of the test class for each test execution (even for theories). If a system gets a large set of devs banging out stuff it less likely to break due a lack of understanding of instance state. Otherwise all the three main test frameworks are much of a much-ness, but this one behavior of xUnit is the "killer app" that makes it the choice.
Glad to see this video, at least the reason is not following what internal dotnet team uses blindly. I have been using xUnit 2 years, previously I used NUnit more than 6 years. The only reason I uses xUnit is because my team/tech lead wants it. I never use xUnit without FluentAssertion. xUnit's assertion is poor compared to NUnit. One of missing feature in xUnit from NUnit is test session fixture setup. xUnit only allows per test/class level setup. I used it before in NUnit and don't see feature equivalent in xUnit. One of the best feature from FluentAssertion is object graph comparison. I use it a lot in my test projects, it's very flexible and powerful.
So my best combination will be NUnit+FluentAssertion. NUnit covers most of the case in my project (assertion helper, setup). I like the new style which is more BDD. It's very flexible, either for single object testing or collection testing. I will use FluentAssertion for object graph testing only. Previously, I have to write my own implementation just to implement this in NUnit.
Nunit allows you to change default behavior of using one class instance for all tests
Which One is preferred for testing MAUI Apps?
Thx, Nick. Lets go next FakeItEasy vs Moq vs NSubstitute, pls )
It's been a while since I'd moved to xUnit, as that's what the new team had + I wanted to check the hype around it, but I still find nUnit to be more CONSISTENT and CLEAR. You can change from per test to per run setup by simply replacing an annotation and when reading existing code it's very clear what it's going to do without looking into docs. Also nUnit works better with multiple sets of data as you can specify what RETURN RESULT you expect, instead of introducing additional 'expectedValue' input -> much cleaner. Plus no nonsense [fact]/[theory] distinction.
Also if you want to use original Asserts I find nUnit ones better and more obvious, plus they support '.That' pattern which is nice. On top of that we've experienced multiple deadlock problems with xUnit, that were terrible to debug, and the author's response to issues in the framework that were pointed out in github wasn't exactly building confidence.
no. you don't need TestFixture unless you have some setup to put in it. TestCase working fine themselves. The one time init showcase is not representative at all, as we have SetUp for it. NUnit is sequential execution by default, so SetUp works pretty solid for, you guessed it, test run setup. And NUnit being translation of JUnit - we can say it was not designed from scratch in the first place.
On the contrary, xUnit was created from scratch when guys realized testing in C# missing a lot with NUnit (say Java) way and it's worth to give C# it's own clean test way. And we don't want to mess with long time living NUnit and make some non-compatible changes - so they decided to create a new testing lib. And they did it the right way so each run is from scratch and test class also from scratch - so your setup not is a constructor - we're good to run all of these in parallel in the most cases.
Not sure it's fair to day NUnit tests are flaky. You need to know tools you're working with. For NUnit you know it's not going to create new test class for every test run. For xUnit - you know it will.
xUnit is missing some key features. For example, there's no way in xUnit to perform setup prior to all tests. There are some third party libraries that fill in the gaps, but they don't work seamlessly with things like IMessageSink.
xUnit also has no way to run arbitrary code after test failure. This can be incredibly useful when unit testing things like MassTransit consumers where you might want to output the message timeline on test failure.
Nick, could you please share your experience of using continuous testing mode in Visual Studio, Rider, NCrunch, etc.
I was using NUnit way back in 2012 because it was popular at that time. Now I'm using xunit because it is much simpler.
What happen if you declare _sut static under XUnit ?
Seems NUnit does it a lot better in my opinion, syntax seems better, more understandable, asserts easier to write.
I only use xUnit nowadays, basically because of the reasons they wrote in the "Why Did we Build xUnit 1.0?" documentation article.
But let me name the most important things: better isolation, by default parallel, more natural constructs (as you mentioned too, C# constructs instead of attributes only).
And yeah, maybe you need to make a video on why MSTest is/was garbage.
Oh yes, when using NUnit after xUnit it's confusing that you need to TearDown class objects so that tests don't clash (usually need to reset mocks in NUnit)
I have used both a lot and to me they are equally good.
Here are my thoughts:
NUnit:
- I prefer reading [Test], [TestCase()] over [Fact], [Theory] - [InlineData()], makes more sense to me.
- It kind a forces you to think about isolating tests better so that they don't clash - should you really reuse the code or use the same class objects? Tests should be dumb and test only what's needed and not care about other tests.
xUnit:
- Default behavior that the class is initialized for each test does make it easier to not think about clashing tests, however this can lead to coupled tests, where you could start initializing common test objects in constructor and then tests can grow, when something changes only for few tests.
- Less code if default behavior is exactly what you need and if you are aware of it
And for all Asserts I like to use global.usings -> FluentAssertions, so doesn't matter which framework is used
the arguments are pretty "random". As said in the intro: a matter of taste. Both are available, both have are large community. Essentially you can't go wrong. It is more important to provide good documentation how to solve common testing issues, e.g. how to genrate read-world data to test DB performance read AND write operations. also: how to add failure to in certain layers (with a random chance of occurance) etc. Most tests, acutally test only that a) the compiler works, b) that the specification - which changes all the time - is being fulfilled.
May I ask your thoughts on using var versus explicit data types? Example: "Guid id = ..." vs "var id = ..." I recently made the switch to using Rider from VS, and I find it odd how Rider always throws warning when I try and use the explicit version, and it recommends I change them all to var.
I’m late here but that’s merely Rider/ReSharper’s default code style. I’ve altered my own so that it doesn’t complain if I use the explicit type. You don’t gain anything from either, it’s down to preference and/or convention.
I do not agree your view on MS Test V2. We are happily using in 20 plus micro services and native clients.
I've used xUnit and MSTest. I tend to like MSTest because it is there out of the box. I've never been very impressed by the It.ShouldNotBe(x); syntax. It is fine, but I wouldn't install a library just for that.
I'd like to know what drives the scoffing about MSTest. I really haven't seen a huge benefit to the other frameworks.
Mostly, I'm just happy if people are writing tests and treat them as a meaningful part of the application.
I use MSTest mostly, nothing wrong with it. Based on your reasoning here I would actually prefer nUnit over xUnit. To each his own, I guess.
The reasoning of "using knowledge you know in c#" can be debatable. In most cases when I have a class of methods. I usually would instantiate a single object and call their methods. I wouldn't be instatiating a class for each method I want to call. Both xUnit and nUnit has its nuances. With nUnit you can think that each class is instantiated once. But how would you achieve separate context? That's why you have a setup and teardown. Other test framework in other languages do that as well.
I understand this is just his preference but I think a more reflective comparison is fairer.
Doesn't really matter tbf As long as the unit is being tested fully just use which ever framework is currently in use on the code base you're working on. I also find that running the class through GPT and asking it to provide a skeleton test suite covering all positives, negatives and edge cases makes Unit testing a whole lot faster. If I'm working on my own projects though it's definitely XUnit :)
In VS Code, the xUnit ITestOutputHelper does NOT write anything out unless I failed test. This "feature" is VERY annoying and make me think switch back to NUnit.
xUnit it is, then, Nick. You say I should do what I like, but so far, following your advices didn't get me bad results, so I will just keep using the "what would Nivk Chapsas do" design pattern 😄
I wasted so much time on XUnit. It was so painful when I tried to use it in integration tests with a db and web api test fixture and varying configurations. You have to make your own plugins and such to parameterize your tests. Parameterization is built in to nunit and is easy to use. So I ended up using XUnit for unit tests and nunit for integration tests which is not ideal.
I was just watching your integration testing course in the other tab. Came to youtube to procrastinate
Mstest is good if your CI/CD pipelines use azure devops because of some feature integrations.
I started using NUnit very long time ago even before MSTest was available. A couple of years ago I switched to XUnit.
I have never used MSTest regularly, but it looks like polished NUnit for me.
From my point of view there are 2 bad things about XUnit: missing documentation and that it is relatively slow (in comparison with others). On the other hand, you can easily run tests in parallel using XUnit, so it is better scalable.
For simple unit tests I do not care. But NUnit is my option for intergration tests. For exeample when you want to isolate tests with transaction scope to keep database state pristine for other test scenarios, in xunit ClassFixture is initialized on a separate async context thus that scope does not carry over to facts (no, async option on transaction scope is not a solution here). also tests ordering or some global inits are harder in xuinit, require custom code. With NUnit all those issues do not exist.
I'm an automation QA, I prefer using Nunit than xUnit, mostly reason is simple, easy to use.
I share similar feelings about NUnit and xUnit, about Assert.Pass(): I don't think there is anything wrong to just say Assert.Equal(true, true), but I go for FluentAssertions usually anyway.
Or just "return;" no?
@@LukeGeorgalas yeah, sometimes you miss obvious ones, right? Although, Assert is still more descriptive, you see Assert and you know it's to do with testing and it is on purpose.
NUnit using the same instance for all Tests in the class hit me hard when working with Unity3D... Also the version used was so old, it didn't support the "instance per test" behavior at all.
In xUnit I'm really fond of TheoryAttribute, and using InlineData/ClassData
Me, who is just getting started with test driven development, completely enchanted by what MSTest can do, and I immediately get to hear its apparently trash :D
Interesting take on why you use xUnit over nUnit. And personally I agree that xUnit makes more sense in several parts of it's implementation.
I just think one of your arguments is kind of a bit flawed. You like xUnit more because it takes C# concepts to represent testing concepts. But on the other hand you also like xUnit that it treats test methods as unrelated to the other test methods in the same class.
Isn't it a C#/OOP concept to group related things in the same class? And those related things share the same state that you define. So from this arguments perspective you should like nUnit more since it uses the correct C#/OOP concept. But you don't because some devs tend to not be good with these concepts.
I mostly use fluentassertions so I don't care too much about the testing framework.
The setup of complex dependencies is a one time thing
When C# added nullable reference types, xUnit became the clear winner.
If you want to do the normal thing and reinstantiate your SUT in each test, then in xUnit, you can declare a field and assign it either at the field declaration, or in the constructor, and that's it. Whereas in NUnit, if you write the equivalent code (assigning the field in your `[SetUp]`), then you get a compiler warning that your SUT field is declared as non-nullable but isn't initialized in the constructor. You have to declare your SUT field as nullable, or use `#nullable disable` on your test class, or not have a field at all and just duplicate the instantiation in each test, or some other unpleasant workaround.
With xUnit, it Just Works.
Exactly, xUnit works much better with nullable reference types. I was also creating sut's and mocks in the SetUp method, I was surprised that Nick is doing it in ctor.
Except that as soon as you need asynchronous setup and teardown methods you'll have to resort to `IAsyncLifeTime` which suffers from the exact same downside.
If you install NUnit.Analyzers, it will recognise the pattern of initialising the field in [SetUp] and automatically disable the warning for you (in addition to many other helpful analysers) so you can declare the field as non-nullable without issue.
I favor NUnit every time because xUnit docs are abysmal.
I've wanted to start using xUnit for new projects but every time I can't because there are literally zero docs about basic functionality like dynamic input for theories. To find anything about xUnit you have to read probably outdated 3rd party articles which is wild.
Awesome video, thank you :)
Lol I literally program around the class initialization problem in nunit all the time. I just add a initialization method on the test initialization attribute, it’s fine.
A Side note is that not only is the test case operated on a single class in NUnit, it's operated on that class in PARALLEL by default, which is a recipe for disaster.
I would add for the people who don't have the option of switching to XUnit you can achieve the separate class per test functionality in NUnit with some annotations on the class with tests in it.
[TestFixture]
[Parallelizable(ParallelScope.All)]
[FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
Nick, yes, please, make a video about the MSTest.
same for me, xUnit is my favorite testing libraby
MSTest is so much better. It creates an instance per test, just like XUnit. It can easily do method level parallelization, which is something XUnit can't do. A lot of the async support is more straightforward.
XUnit
For Assert.Pass in xUnit, can't you just return?
The test will be success if no asserts fail, so by returning it would be success.
Assert.Pass shows intent better though.
It's not as simple. Assert.Pass will work from any method or nesting level. return needs to be specially handled to be top level in xunit. It's possible, but you have to compromise with how you write the test
@@nickchapsas ah, yeah, I didn't think about Assert.Pass in a method other than the test method.
I use MSTest.
Either you haven’t worked with NUnit or you don’t know, but in NUnit you can configure the creation of objects and destruction (cleaning) for each test or group of tests. Why the hell mislead people?
Every job I've had for like forever... we're using MSTest and I don't know why. Nobody seems to know why. We just use it.
Same. 😅 Until now... now we have no unit tests. I'm about to create the first ones, so here I am. 🤣 I'm leaning towards NUnit, though it could be I'm just more used to the syntax, even with all the inconveniences...
xUnit - I like it and its nice that if i do Java i can use xUnit there too
I feel like everything discussed here is about features of the test runners that are intended to make writing tests that have complicated setup and finalize easier. However, I am strongly in the camp of, if your tests are hard to write, you have done something wrong. For one, it means you wrote the code first, which is a big no-no in TTD. Second, it tells you that you didn't write testable code which you wouldn't have done had you written the tests first. Write your tests first, and your tests become so simple that you don't need to worry about these extra features of the test runner. The fix is not to use the complex pieces of the test runner. The fix is to refactor the code to be testable.
MSTest!)))
I like the default of xUnit as well. But NUnit has a FixtureLifeCycle attribute. With LifeCycle.InstancePerTestCase you can ensure your classes will be instantiated the same way as in xUnit, with the constructor and IDisposable. You can also mark your assembly to use this for all the classes. Very handy when running test in full parallel, because SetUp is not 100% safe.
My new workplace is stuck at mstest its so trash my god.
What's wrong with it?
Im still using nunit because of only one frature - testing internal classes and interfaces without exposing them. For those who saying you should test only public things, I dont agree
That's a hint that you(or whoever) didn't write testable code. The defect is in the code being tested, not the lack of features in the test runner.
@@tunawithmayo Perfectly normal to have internals that you unit test when creating a library. If its in application code then its very questionable.
That said, I use xUnit for this and just `InternalsVisibleTo` the test assembly.
@@Denominus Well, that doesnt work if you have some kind of component test wrapper where you put tested interface in generic base class. That setup requires you to have internal test class (because you cannot have public class and inheriting from internal, even in generic argument). Unfortunatelly xunit cannot handle it. Nunit works perfectly well with testfixture attribute
I came to the video looking for why you'd be using NUnit not xUnit 😁
A lot of people use xUnit because it's getting Microsoft's 1st class support (in docs and examples, etc.) since the creator joined the company.
I use NUnit because I'm an old fart and I haven't found a need to switch to xUnit yet. But I'd be happy to use xUnit if I'm put on a project that already uses it.
[TestContext] attribute in NUnit is not required. But overall good video.