Base solution for your next web application
Open Closed

Improving tests performance #4793


User avatar
0
easy2u created

Since tests that came with the template and all samples published on the web, execute pretty long, given the number of them that is supposed to be in the final developed solution, is there a way to improve performance of them, so that they don't execute 5 seconds each? If final solution has 4000 tests, it would take more than 5 hours to execute them all. That seems to be unacceptable for a good CI.

I understand that they are integration tests and that is why they take long time to execute, but is there an easy way to perform setup only once for a larger group of tests, so that individual tests can execute faster (have only one "setup" of 4.5s instead of X * 4.5s)?


5 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    From our email response;

    Tests in AspNet Zero project must be considered as Integration Tests, not Unit Tests. So, it is normal that an Integration Test takes a few seconds to execute.

    Effort uses an In-Memory database, so replacing it with another alternative probably will make tests slower.

  • User Avatar
    0
    easy2u created

    From my reply to the statement from the e-mail

    I understand that they are integration tests

    but is there an easy way to perform setup only once for a larger group of tests

    So the focus of the question is on the "is there an easy way to perform setup only once", so that whole setup is not repeatedly done for each test? Fact that they are not unit tests, but integration tests, does not change a thing. Both can have heavy setup and both can have common heavy setup extracted to happen only once (with some drawbacks eventually). Question is if there is an easy way with boilerplate/ASP.NET zero "wrapper" around core methods to do this when inheriting from "AbpIntegratedTestBase" class? Is there a sample how to do this?

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    is there an easy way to perform setup only once"

    Even If you manage to do this, it will cause problems with the tests.

    in AspNet Zero and ABP Frameworks, each test is isolated from other tests. Tests are not affecting each other. So, "setup only once" approach will break that rule and tests will affect each other. This is not a suggested way for tests.

  • User Avatar
    0
    strix20 created

    Integration tests will always take a long time, and because of that, they aren't suited for CI.

    These types of tests are generally run on nightly build servers, as opposed to per commit like you would do with unit tests.

    We created a second test project (technically two test projects, one for unit tests for domain, and one for unit tests for application.)

    The only tests we include in our CI configuration in team city are the unit tests. They execute very quickly, with minimal impact on our build servers.

    In general, I find unit tests to be much more valuable tests, because they tell you exactly where your code is failing, whereas integration tests only really tell you if your layers are connected properly. If an integration test fails, it's not immediately clear where the failure is occurring. Add to that the greater potential for unexpected issues related to things like differences between in-memory db and sql server, and you can spend a lot of time running in circles for a non-issue.

    That's not to say they aren't valuable. They absolutely are. They just shouldn't serve as a replacement for unit tests, and if you're adding your own tests to the project, I would recommend investing the time in unit tests over integration tests, if you're constrained on development time.

  • User Avatar
    0
    alper created
    Support Team

    Hi,

    xUnit has a very good feature called Shared Context So there is a canonical way to share features between tests. Check out the documentation <a class="postlink" href="https://xunit.github.io/docs/shared-context.html">https://xunit.github.io/docs/shared-context.html</a>

    Create a class doing the fixture:

    public class DatabaseFixture : IDisposable
        {
            public DatabaseFixture()
            {
                Db = new SqlConnection("MyConnectionString");
    
                // ... initialize data in the test database ...
            }
    
            public void Dispose()
            {
                // ... clean up test data from the database ...
            }
    
            public SqlConnection Db { get; private set; }
        }
    

    A dummy class bearing the CollectionDefinition attribute. This class allows Xunit to create a test collection, and will use the given fixture for all test classes of the collection.

    [CollectionDefinition("Database collection")]
        public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
        {
            // This class has no code, and is never created. Its purpose is simply
            // to be the place to apply [CollectionDefinition] and all the
            // ICollectionFixture<> interfaces.
        }
    

    Then you need to add the collection name over all your test classes. The test classes can receive the fixture through the constructor.

    [Collection("Database collection")]
        public class DatabaseTestClass1
        {
            DatabaseFixture fixture;
    
            public DatabaseTestClass1(DatabaseFixture fixture)
            {
                this.fixture = fixture;
            }
        }