Is a Unit test considered brittle if it fails when the business logic changes?












16














Please see the code below; it tests to see if a person with Gender of female is eligible for offer1:



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id,"Offer1");
Assert.False(offer1.IsEligible(person));
}


This unit test succeeds. However, it will fail if 'Offer1' is offered to females in future.



Is it acceptable to say - if the business logic surrounding offer 1 changes then the unit test must change. Please note that in some cases (for some offers) the business logic is changed in the database like this:



update Offers set Gender='M' where offer=1;


and in some cases in the domain model like this:



if (Gender=Gender.Male)
{
//do something
}


Please also note that in some cases the domain logic behind offers changes regularly and in some cases it does not.










share|improve this question






















  • Think from another angle: Do you want to have tests which not failed when you change logic in the system under the test?
    – Fabio
    22 hours ago












  • Only two genders?
    – Martin Schröder
    11 hours ago
















16














Please see the code below; it tests to see if a person with Gender of female is eligible for offer1:



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id,"Offer1");
Assert.False(offer1.IsEligible(person));
}


This unit test succeeds. However, it will fail if 'Offer1' is offered to females in future.



Is it acceptable to say - if the business logic surrounding offer 1 changes then the unit test must change. Please note that in some cases (for some offers) the business logic is changed in the database like this:



update Offers set Gender='M' where offer=1;


and in some cases in the domain model like this:



if (Gender=Gender.Male)
{
//do something
}


Please also note that in some cases the domain logic behind offers changes regularly and in some cases it does not.










share|improve this question






















  • Think from another angle: Do you want to have tests which not failed when you change logic in the system under the test?
    – Fabio
    22 hours ago












  • Only two genders?
    – Martin Schröder
    11 hours ago














16












16








16


2





Please see the code below; it tests to see if a person with Gender of female is eligible for offer1:



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id,"Offer1");
Assert.False(offer1.IsEligible(person));
}


This unit test succeeds. However, it will fail if 'Offer1' is offered to females in future.



Is it acceptable to say - if the business logic surrounding offer 1 changes then the unit test must change. Please note that in some cases (for some offers) the business logic is changed in the database like this:



update Offers set Gender='M' where offer=1;


and in some cases in the domain model like this:



if (Gender=Gender.Male)
{
//do something
}


Please also note that in some cases the domain logic behind offers changes regularly and in some cases it does not.










share|improve this question













Please see the code below; it tests to see if a person with Gender of female is eligible for offer1:



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id,"Offer1");
Assert.False(offer1.IsEligible(person));
}


This unit test succeeds. However, it will fail if 'Offer1' is offered to females in future.



Is it acceptable to say - if the business logic surrounding offer 1 changes then the unit test must change. Please note that in some cases (for some offers) the business logic is changed in the database like this:



update Offers set Gender='M' where offer=1;


and in some cases in the domain model like this:



if (Gender=Gender.Male)
{
//do something
}


Please also note that in some cases the domain logic behind offers changes regularly and in some cases it does not.







c# unit-testing domain-driven-design xunit






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked yesterday









w0051977

2,71232249




2,71232249












  • Think from another angle: Do you want to have tests which not failed when you change logic in the system under the test?
    – Fabio
    22 hours ago












  • Only two genders?
    – Martin Schröder
    11 hours ago


















  • Think from another angle: Do you want to have tests which not failed when you change logic in the system under the test?
    – Fabio
    22 hours ago












  • Only two genders?
    – Martin Schröder
    11 hours ago
















Think from another angle: Do you want to have tests which not failed when you change logic in the system under the test?
– Fabio
22 hours ago






Think from another angle: Do you want to have tests which not failed when you change logic in the system under the test?
– Fabio
22 hours ago














Only two genders?
– Martin Schröder
11 hours ago




Only two genders?
– Martin Schröder
11 hours ago










2 Answers
2






active

oldest

votes


















58














This is not brittle in the usual sense. A unit test is considered brittle if it breaks due to implementation changes which does not affect the behavior under test. But if the business logic itself changes, then a test of this logic is supposed to break.



That said, if the business logic indeed changes often, perhaps it is not appropriate to hardcode the expectations into the unit tests. Instead you could test if the configurations in the database affects the offers as expected.



The name of the test Returns False When Given A Person With A Gender Of Female does not describe a business rule. A business rule would be something like Offers Applicable to M should not be applied to persons of gender F.



So you could write a test that confirms that if an offer is defined as only applicable to type M persons, then a type F person will not be indicated as eligible for it. This test will ensure the logic works even if the configuration of the specific offers change.






share|improve this answer























  • @JaquesB, then it would not be a unit test? or would it? I believe it would be an integration test if the database was involved. Is that right? Are you saying don't use unit tests if the business logic changes a lot?
    – w0051977
    yesterday










  • @w0051977: Depends how you write the test. If the test includes actually changing changing something in a database, then it would be an integration test.
    – JacquesB
    yesterday






  • 1




    @w0051977 better idea - don't have the repository be a dependency of the component responsible for implementing business rules. Have a higher-level orchestration that calls the repository and then invokes the business rules. Now you can unit test the business rules in isolation.
    – Ant P
    yesterday






  • 4




    @w0051977 of course it is - tests specify behaviour. If the rules governing the behaviour of a component change, then the tests must change to reflect the change in behaviour. What shouldn't need to change are tests that specify behaviours other than what is changing. If the behaviour is determined by the database, then a test covering some other code is inherently unrelated and should not need to change unless that database logic is within the scope of the test. That scope is for you to define and the semantics of whether it's a unit test or integration test are not really important.
    – Ant P
    yesterday








  • 2




    @w0051977 extending this idea somewhat, if business logic changes or a bug is fixed and the tests don't need adjusting, it's a sign that the tests aren't covering sufficient cases and should generally be expanded.
    – Morgen
    yesterday



















9














When the property is defined in the production database (or a clone for testing), this is not a unit test. A unit test checks a unit of work and does not require a particular external state to work. This assumes that Offer1 is defined in the database to be a male-only offer. That's external state. So this is more of an integration test, specifically a system or acceptance test. Note that acceptance tests are often not scripted (not run in a test framework but manually performed by human beings).



When the property is defined in the domain model with an if statement, the same test is a unit test. And it may be brittle. But the real problem is that the code is brittle. As a general rule, your code will be more resilient if business behavior is configurable rather than hard coded. Because a rush deployment to fix a small coding error should be rare. But a business requirement changing without notice is just a Tuesday (something that happens weekly).



You may be using a unit test framework to run the test. But unit test frameworks are not limited to running unit tests. They can and do run integration tests as well.



If you were writing a unit test, you would create both person and offer1 from the ground up with no reliance on database state. Something like



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
offer1.markLimitedToGender("M");

Assert.False(offer1.IsEligible(person));
}


Note that this doesn't change based on the business logic. It's not asserting that offer1 rejects females. It is making offer1 the type of offer that rejects females.



You might create and configure the database as part of the test. In C#, using NUnit, or in Java's JUnit, you would set up the database in a Setup method. Presumably your test framework has a similar notion. In that method, you could insert records into the database with SQL.



If it is hard for you to write code that substitutes a test database for the production database, that sounds like a testing weakness in your application. For testing, it would be better to use something like dependency injection that allows for substitution. Then you could write tests that are independent of the current business rules.



A side benefit of this is that it is often easier for the business owner (not necessarily the corporate owner, more like the person responsible for this product in the corporate hierarchy) to configure the business rules directly. Because if you have this kind of technical framework, it is easy to allow the business owner to use a user interface (UI) to configure the offer. The business owner would select the limitation in the UI, and it would issue the markLimitedToGender("M") call. Then when the offer is persisted to the database, it would store this. But you wouldn't need to store the offer to use it. So your tests could create and configure an offer that doesn't exist in the database.



In your system as described, the business owner would have to put in a request to the technical group, which would issue the appropriate SQL and update the tests. Or the technical group has to edit your code and tests (or tests then code). That seems a rather heavyweight approach. You can do it. But your software (not just your testing) would be less brittle if you did not have to do so.



TL;DR: you can write tests like this, but you may be better off writing your software so you don't have to do so.






share|improve this answer























  • I tool the freedom to improve some minor details in your answer. Please check if I got your intentions right.
    – Doc Brown
    yesterday










  • There is no indication in the original post that a database is involved. So claiming that it assumes that Offer1 is already in the database is bizarre.
    – Winston Ewert
    yesterday






  • 1




    @WinstonEwert: there is a clear indication, you have to read the question more carefully. I did not realize it at the first read, too, but it is indeed what the OP is talking of.
    – Doc Brown
    yesterday












  • @mdfst13, I'm sorry I missed that. However, what the OP is saying is that the conditions are sometimes in a database and sometimes in the domain model. Your answer is perfectly fine for the first case, and irreverently in the second. If you'll edit your answer to clarify that point, I'll remove my hasty downvote.
    – Winston Ewert
    yesterday











Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "131"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f384509%2fis-a-unit-test-considered-brittle-if-it-fails-when-the-business-logic-changes%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









58














This is not brittle in the usual sense. A unit test is considered brittle if it breaks due to implementation changes which does not affect the behavior under test. But if the business logic itself changes, then a test of this logic is supposed to break.



That said, if the business logic indeed changes often, perhaps it is not appropriate to hardcode the expectations into the unit tests. Instead you could test if the configurations in the database affects the offers as expected.



The name of the test Returns False When Given A Person With A Gender Of Female does not describe a business rule. A business rule would be something like Offers Applicable to M should not be applied to persons of gender F.



So you could write a test that confirms that if an offer is defined as only applicable to type M persons, then a type F person will not be indicated as eligible for it. This test will ensure the logic works even if the configuration of the specific offers change.






share|improve this answer























  • @JaquesB, then it would not be a unit test? or would it? I believe it would be an integration test if the database was involved. Is that right? Are you saying don't use unit tests if the business logic changes a lot?
    – w0051977
    yesterday










  • @w0051977: Depends how you write the test. If the test includes actually changing changing something in a database, then it would be an integration test.
    – JacquesB
    yesterday






  • 1




    @w0051977 better idea - don't have the repository be a dependency of the component responsible for implementing business rules. Have a higher-level orchestration that calls the repository and then invokes the business rules. Now you can unit test the business rules in isolation.
    – Ant P
    yesterday






  • 4




    @w0051977 of course it is - tests specify behaviour. If the rules governing the behaviour of a component change, then the tests must change to reflect the change in behaviour. What shouldn't need to change are tests that specify behaviours other than what is changing. If the behaviour is determined by the database, then a test covering some other code is inherently unrelated and should not need to change unless that database logic is within the scope of the test. That scope is for you to define and the semantics of whether it's a unit test or integration test are not really important.
    – Ant P
    yesterday








  • 2




    @w0051977 extending this idea somewhat, if business logic changes or a bug is fixed and the tests don't need adjusting, it's a sign that the tests aren't covering sufficient cases and should generally be expanded.
    – Morgen
    yesterday
















58














This is not brittle in the usual sense. A unit test is considered brittle if it breaks due to implementation changes which does not affect the behavior under test. But if the business logic itself changes, then a test of this logic is supposed to break.



That said, if the business logic indeed changes often, perhaps it is not appropriate to hardcode the expectations into the unit tests. Instead you could test if the configurations in the database affects the offers as expected.



The name of the test Returns False When Given A Person With A Gender Of Female does not describe a business rule. A business rule would be something like Offers Applicable to M should not be applied to persons of gender F.



So you could write a test that confirms that if an offer is defined as only applicable to type M persons, then a type F person will not be indicated as eligible for it. This test will ensure the logic works even if the configuration of the specific offers change.






share|improve this answer























  • @JaquesB, then it would not be a unit test? or would it? I believe it would be an integration test if the database was involved. Is that right? Are you saying don't use unit tests if the business logic changes a lot?
    – w0051977
    yesterday










  • @w0051977: Depends how you write the test. If the test includes actually changing changing something in a database, then it would be an integration test.
    – JacquesB
    yesterday






  • 1




    @w0051977 better idea - don't have the repository be a dependency of the component responsible for implementing business rules. Have a higher-level orchestration that calls the repository and then invokes the business rules. Now you can unit test the business rules in isolation.
    – Ant P
    yesterday






  • 4




    @w0051977 of course it is - tests specify behaviour. If the rules governing the behaviour of a component change, then the tests must change to reflect the change in behaviour. What shouldn't need to change are tests that specify behaviours other than what is changing. If the behaviour is determined by the database, then a test covering some other code is inherently unrelated and should not need to change unless that database logic is within the scope of the test. That scope is for you to define and the semantics of whether it's a unit test or integration test are not really important.
    – Ant P
    yesterday








  • 2




    @w0051977 extending this idea somewhat, if business logic changes or a bug is fixed and the tests don't need adjusting, it's a sign that the tests aren't covering sufficient cases and should generally be expanded.
    – Morgen
    yesterday














58












58








58






This is not brittle in the usual sense. A unit test is considered brittle if it breaks due to implementation changes which does not affect the behavior under test. But if the business logic itself changes, then a test of this logic is supposed to break.



That said, if the business logic indeed changes often, perhaps it is not appropriate to hardcode the expectations into the unit tests. Instead you could test if the configurations in the database affects the offers as expected.



The name of the test Returns False When Given A Person With A Gender Of Female does not describe a business rule. A business rule would be something like Offers Applicable to M should not be applied to persons of gender F.



So you could write a test that confirms that if an offer is defined as only applicable to type M persons, then a type F person will not be indicated as eligible for it. This test will ensure the logic works even if the configuration of the specific offers change.






share|improve this answer














This is not brittle in the usual sense. A unit test is considered brittle if it breaks due to implementation changes which does not affect the behavior under test. But if the business logic itself changes, then a test of this logic is supposed to break.



That said, if the business logic indeed changes often, perhaps it is not appropriate to hardcode the expectations into the unit tests. Instead you could test if the configurations in the database affects the offers as expected.



The name of the test Returns False When Given A Person With A Gender Of Female does not describe a business rule. A business rule would be something like Offers Applicable to M should not be applied to persons of gender F.



So you could write a test that confirms that if an offer is defined as only applicable to type M persons, then a type F person will not be indicated as eligible for it. This test will ensure the logic works even if the configuration of the specific offers change.







share|improve this answer














share|improve this answer



share|improve this answer








edited yesterday









Doc Brown

130k22239378




130k22239378










answered yesterday









JacquesB

41.4k1685121




41.4k1685121












  • @JaquesB, then it would not be a unit test? or would it? I believe it would be an integration test if the database was involved. Is that right? Are you saying don't use unit tests if the business logic changes a lot?
    – w0051977
    yesterday










  • @w0051977: Depends how you write the test. If the test includes actually changing changing something in a database, then it would be an integration test.
    – JacquesB
    yesterday






  • 1




    @w0051977 better idea - don't have the repository be a dependency of the component responsible for implementing business rules. Have a higher-level orchestration that calls the repository and then invokes the business rules. Now you can unit test the business rules in isolation.
    – Ant P
    yesterday






  • 4




    @w0051977 of course it is - tests specify behaviour. If the rules governing the behaviour of a component change, then the tests must change to reflect the change in behaviour. What shouldn't need to change are tests that specify behaviours other than what is changing. If the behaviour is determined by the database, then a test covering some other code is inherently unrelated and should not need to change unless that database logic is within the scope of the test. That scope is for you to define and the semantics of whether it's a unit test or integration test are not really important.
    – Ant P
    yesterday








  • 2




    @w0051977 extending this idea somewhat, if business logic changes or a bug is fixed and the tests don't need adjusting, it's a sign that the tests aren't covering sufficient cases and should generally be expanded.
    – Morgen
    yesterday


















  • @JaquesB, then it would not be a unit test? or would it? I believe it would be an integration test if the database was involved. Is that right? Are you saying don't use unit tests if the business logic changes a lot?
    – w0051977
    yesterday










  • @w0051977: Depends how you write the test. If the test includes actually changing changing something in a database, then it would be an integration test.
    – JacquesB
    yesterday






  • 1




    @w0051977 better idea - don't have the repository be a dependency of the component responsible for implementing business rules. Have a higher-level orchestration that calls the repository and then invokes the business rules. Now you can unit test the business rules in isolation.
    – Ant P
    yesterday






  • 4




    @w0051977 of course it is - tests specify behaviour. If the rules governing the behaviour of a component change, then the tests must change to reflect the change in behaviour. What shouldn't need to change are tests that specify behaviours other than what is changing. If the behaviour is determined by the database, then a test covering some other code is inherently unrelated and should not need to change unless that database logic is within the scope of the test. That scope is for you to define and the semantics of whether it's a unit test or integration test are not really important.
    – Ant P
    yesterday








  • 2




    @w0051977 extending this idea somewhat, if business logic changes or a bug is fixed and the tests don't need adjusting, it's a sign that the tests aren't covering sufficient cases and should generally be expanded.
    – Morgen
    yesterday
















@JaquesB, then it would not be a unit test? or would it? I believe it would be an integration test if the database was involved. Is that right? Are you saying don't use unit tests if the business logic changes a lot?
– w0051977
yesterday




@JaquesB, then it would not be a unit test? or would it? I believe it would be an integration test if the database was involved. Is that right? Are you saying don't use unit tests if the business logic changes a lot?
– w0051977
yesterday












@w0051977: Depends how you write the test. If the test includes actually changing changing something in a database, then it would be an integration test.
– JacquesB
yesterday




@w0051977: Depends how you write the test. If the test includes actually changing changing something in a database, then it would be an integration test.
– JacquesB
yesterday




1




1




@w0051977 better idea - don't have the repository be a dependency of the component responsible for implementing business rules. Have a higher-level orchestration that calls the repository and then invokes the business rules. Now you can unit test the business rules in isolation.
– Ant P
yesterday




@w0051977 better idea - don't have the repository be a dependency of the component responsible for implementing business rules. Have a higher-level orchestration that calls the repository and then invokes the business rules. Now you can unit test the business rules in isolation.
– Ant P
yesterday




4




4




@w0051977 of course it is - tests specify behaviour. If the rules governing the behaviour of a component change, then the tests must change to reflect the change in behaviour. What shouldn't need to change are tests that specify behaviours other than what is changing. If the behaviour is determined by the database, then a test covering some other code is inherently unrelated and should not need to change unless that database logic is within the scope of the test. That scope is for you to define and the semantics of whether it's a unit test or integration test are not really important.
– Ant P
yesterday






@w0051977 of course it is - tests specify behaviour. If the rules governing the behaviour of a component change, then the tests must change to reflect the change in behaviour. What shouldn't need to change are tests that specify behaviours other than what is changing. If the behaviour is determined by the database, then a test covering some other code is inherently unrelated and should not need to change unless that database logic is within the scope of the test. That scope is for you to define and the semantics of whether it's a unit test or integration test are not really important.
– Ant P
yesterday






2




2




@w0051977 extending this idea somewhat, if business logic changes or a bug is fixed and the tests don't need adjusting, it's a sign that the tests aren't covering sufficient cases and should generally be expanded.
– Morgen
yesterday




@w0051977 extending this idea somewhat, if business logic changes or a bug is fixed and the tests don't need adjusting, it's a sign that the tests aren't covering sufficient cases and should generally be expanded.
– Morgen
yesterday













9














When the property is defined in the production database (or a clone for testing), this is not a unit test. A unit test checks a unit of work and does not require a particular external state to work. This assumes that Offer1 is defined in the database to be a male-only offer. That's external state. So this is more of an integration test, specifically a system or acceptance test. Note that acceptance tests are often not scripted (not run in a test framework but manually performed by human beings).



When the property is defined in the domain model with an if statement, the same test is a unit test. And it may be brittle. But the real problem is that the code is brittle. As a general rule, your code will be more resilient if business behavior is configurable rather than hard coded. Because a rush deployment to fix a small coding error should be rare. But a business requirement changing without notice is just a Tuesday (something that happens weekly).



You may be using a unit test framework to run the test. But unit test frameworks are not limited to running unit tests. They can and do run integration tests as well.



If you were writing a unit test, you would create both person and offer1 from the ground up with no reliance on database state. Something like



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
offer1.markLimitedToGender("M");

Assert.False(offer1.IsEligible(person));
}


Note that this doesn't change based on the business logic. It's not asserting that offer1 rejects females. It is making offer1 the type of offer that rejects females.



You might create and configure the database as part of the test. In C#, using NUnit, or in Java's JUnit, you would set up the database in a Setup method. Presumably your test framework has a similar notion. In that method, you could insert records into the database with SQL.



If it is hard for you to write code that substitutes a test database for the production database, that sounds like a testing weakness in your application. For testing, it would be better to use something like dependency injection that allows for substitution. Then you could write tests that are independent of the current business rules.



A side benefit of this is that it is often easier for the business owner (not necessarily the corporate owner, more like the person responsible for this product in the corporate hierarchy) to configure the business rules directly. Because if you have this kind of technical framework, it is easy to allow the business owner to use a user interface (UI) to configure the offer. The business owner would select the limitation in the UI, and it would issue the markLimitedToGender("M") call. Then when the offer is persisted to the database, it would store this. But you wouldn't need to store the offer to use it. So your tests could create and configure an offer that doesn't exist in the database.



In your system as described, the business owner would have to put in a request to the technical group, which would issue the appropriate SQL and update the tests. Or the technical group has to edit your code and tests (or tests then code). That seems a rather heavyweight approach. You can do it. But your software (not just your testing) would be less brittle if you did not have to do so.



TL;DR: you can write tests like this, but you may be better off writing your software so you don't have to do so.






share|improve this answer























  • I tool the freedom to improve some minor details in your answer. Please check if I got your intentions right.
    – Doc Brown
    yesterday










  • There is no indication in the original post that a database is involved. So claiming that it assumes that Offer1 is already in the database is bizarre.
    – Winston Ewert
    yesterday






  • 1




    @WinstonEwert: there is a clear indication, you have to read the question more carefully. I did not realize it at the first read, too, but it is indeed what the OP is talking of.
    – Doc Brown
    yesterday












  • @mdfst13, I'm sorry I missed that. However, what the OP is saying is that the conditions are sometimes in a database and sometimes in the domain model. Your answer is perfectly fine for the first case, and irreverently in the second. If you'll edit your answer to clarify that point, I'll remove my hasty downvote.
    – Winston Ewert
    yesterday
















9














When the property is defined in the production database (or a clone for testing), this is not a unit test. A unit test checks a unit of work and does not require a particular external state to work. This assumes that Offer1 is defined in the database to be a male-only offer. That's external state. So this is more of an integration test, specifically a system or acceptance test. Note that acceptance tests are often not scripted (not run in a test framework but manually performed by human beings).



When the property is defined in the domain model with an if statement, the same test is a unit test. And it may be brittle. But the real problem is that the code is brittle. As a general rule, your code will be more resilient if business behavior is configurable rather than hard coded. Because a rush deployment to fix a small coding error should be rare. But a business requirement changing without notice is just a Tuesday (something that happens weekly).



You may be using a unit test framework to run the test. But unit test frameworks are not limited to running unit tests. They can and do run integration tests as well.



If you were writing a unit test, you would create both person and offer1 from the ground up with no reliance on database state. Something like



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
offer1.markLimitedToGender("M");

Assert.False(offer1.IsEligible(person));
}


Note that this doesn't change based on the business logic. It's not asserting that offer1 rejects females. It is making offer1 the type of offer that rejects females.



You might create and configure the database as part of the test. In C#, using NUnit, or in Java's JUnit, you would set up the database in a Setup method. Presumably your test framework has a similar notion. In that method, you could insert records into the database with SQL.



If it is hard for you to write code that substitutes a test database for the production database, that sounds like a testing weakness in your application. For testing, it would be better to use something like dependency injection that allows for substitution. Then you could write tests that are independent of the current business rules.



A side benefit of this is that it is often easier for the business owner (not necessarily the corporate owner, more like the person responsible for this product in the corporate hierarchy) to configure the business rules directly. Because if you have this kind of technical framework, it is easy to allow the business owner to use a user interface (UI) to configure the offer. The business owner would select the limitation in the UI, and it would issue the markLimitedToGender("M") call. Then when the offer is persisted to the database, it would store this. But you wouldn't need to store the offer to use it. So your tests could create and configure an offer that doesn't exist in the database.



In your system as described, the business owner would have to put in a request to the technical group, which would issue the appropriate SQL and update the tests. Or the technical group has to edit your code and tests (or tests then code). That seems a rather heavyweight approach. You can do it. But your software (not just your testing) would be less brittle if you did not have to do so.



TL;DR: you can write tests like this, but you may be better off writing your software so you don't have to do so.






share|improve this answer























  • I tool the freedom to improve some minor details in your answer. Please check if I got your intentions right.
    – Doc Brown
    yesterday










  • There is no indication in the original post that a database is involved. So claiming that it assumes that Offer1 is already in the database is bizarre.
    – Winston Ewert
    yesterday






  • 1




    @WinstonEwert: there is a clear indication, you have to read the question more carefully. I did not realize it at the first read, too, but it is indeed what the OP is talking of.
    – Doc Brown
    yesterday












  • @mdfst13, I'm sorry I missed that. However, what the OP is saying is that the conditions are sometimes in a database and sometimes in the domain model. Your answer is perfectly fine for the first case, and irreverently in the second. If you'll edit your answer to clarify that point, I'll remove my hasty downvote.
    – Winston Ewert
    yesterday














9












9








9






When the property is defined in the production database (or a clone for testing), this is not a unit test. A unit test checks a unit of work and does not require a particular external state to work. This assumes that Offer1 is defined in the database to be a male-only offer. That's external state. So this is more of an integration test, specifically a system or acceptance test. Note that acceptance tests are often not scripted (not run in a test framework but manually performed by human beings).



When the property is defined in the domain model with an if statement, the same test is a unit test. And it may be brittle. But the real problem is that the code is brittle. As a general rule, your code will be more resilient if business behavior is configurable rather than hard coded. Because a rush deployment to fix a small coding error should be rare. But a business requirement changing without notice is just a Tuesday (something that happens weekly).



You may be using a unit test framework to run the test. But unit test frameworks are not limited to running unit tests. They can and do run integration tests as well.



If you were writing a unit test, you would create both person and offer1 from the ground up with no reliance on database state. Something like



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
offer1.markLimitedToGender("M");

Assert.False(offer1.IsEligible(person));
}


Note that this doesn't change based on the business logic. It's not asserting that offer1 rejects females. It is making offer1 the type of offer that rejects females.



You might create and configure the database as part of the test. In C#, using NUnit, or in Java's JUnit, you would set up the database in a Setup method. Presumably your test framework has a similar notion. In that method, you could insert records into the database with SQL.



If it is hard for you to write code that substitutes a test database for the production database, that sounds like a testing weakness in your application. For testing, it would be better to use something like dependency injection that allows for substitution. Then you could write tests that are independent of the current business rules.



A side benefit of this is that it is often easier for the business owner (not necessarily the corporate owner, more like the person responsible for this product in the corporate hierarchy) to configure the business rules directly. Because if you have this kind of technical framework, it is easy to allow the business owner to use a user interface (UI) to configure the offer. The business owner would select the limitation in the UI, and it would issue the markLimitedToGender("M") call. Then when the offer is persisted to the database, it would store this. But you wouldn't need to store the offer to use it. So your tests could create and configure an offer that doesn't exist in the database.



In your system as described, the business owner would have to put in a request to the technical group, which would issue the appropriate SQL and update the tests. Or the technical group has to edit your code and tests (or tests then code). That seems a rather heavyweight approach. You can do it. But your software (not just your testing) would be less brittle if you did not have to do so.



TL;DR: you can write tests like this, but you may be better off writing your software so you don't have to do so.






share|improve this answer














When the property is defined in the production database (or a clone for testing), this is not a unit test. A unit test checks a unit of work and does not require a particular external state to work. This assumes that Offer1 is defined in the database to be a male-only offer. That's external state. So this is more of an integration test, specifically a system or acceptance test. Note that acceptance tests are often not scripted (not run in a test framework but manually performed by human beings).



When the property is defined in the domain model with an if statement, the same test is a unit test. And it may be brittle. But the real problem is that the code is brittle. As a general rule, your code will be more resilient if business behavior is configurable rather than hard coded. Because a rush deployment to fix a small coding error should be rare. But a business requirement changing without notice is just a Tuesday (something that happens weekly).



You may be using a unit test framework to run the test. But unit test frameworks are not limited to running unit tests. They can and do run integration tests as well.



If you were writing a unit test, you would create both person and offer1 from the ground up with no reliance on database state. Something like



[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
var personId = Guid.NewGuid();
var gender = "F";
var person = new Person(personId, gender);

var id = Guid.NewGuid();
var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
offer1.markLimitedToGender("M");

Assert.False(offer1.IsEligible(person));
}


Note that this doesn't change based on the business logic. It's not asserting that offer1 rejects females. It is making offer1 the type of offer that rejects females.



You might create and configure the database as part of the test. In C#, using NUnit, or in Java's JUnit, you would set up the database in a Setup method. Presumably your test framework has a similar notion. In that method, you could insert records into the database with SQL.



If it is hard for you to write code that substitutes a test database for the production database, that sounds like a testing weakness in your application. For testing, it would be better to use something like dependency injection that allows for substitution. Then you could write tests that are independent of the current business rules.



A side benefit of this is that it is often easier for the business owner (not necessarily the corporate owner, more like the person responsible for this product in the corporate hierarchy) to configure the business rules directly. Because if you have this kind of technical framework, it is easy to allow the business owner to use a user interface (UI) to configure the offer. The business owner would select the limitation in the UI, and it would issue the markLimitedToGender("M") call. Then when the offer is persisted to the database, it would store this. But you wouldn't need to store the offer to use it. So your tests could create and configure an offer that doesn't exist in the database.



In your system as described, the business owner would have to put in a request to the technical group, which would issue the appropriate SQL and update the tests. Or the technical group has to edit your code and tests (or tests then code). That seems a rather heavyweight approach. You can do it. But your software (not just your testing) would be less brittle if you did not have to do so.



TL;DR: you can write tests like this, but you may be better off writing your software so you don't have to do so.







share|improve this answer














share|improve this answer



share|improve this answer








edited yesterday

























answered yesterday









mdfst13

25213




25213












  • I tool the freedom to improve some minor details in your answer. Please check if I got your intentions right.
    – Doc Brown
    yesterday










  • There is no indication in the original post that a database is involved. So claiming that it assumes that Offer1 is already in the database is bizarre.
    – Winston Ewert
    yesterday






  • 1




    @WinstonEwert: there is a clear indication, you have to read the question more carefully. I did not realize it at the first read, too, but it is indeed what the OP is talking of.
    – Doc Brown
    yesterday












  • @mdfst13, I'm sorry I missed that. However, what the OP is saying is that the conditions are sometimes in a database and sometimes in the domain model. Your answer is perfectly fine for the first case, and irreverently in the second. If you'll edit your answer to clarify that point, I'll remove my hasty downvote.
    – Winston Ewert
    yesterday


















  • I tool the freedom to improve some minor details in your answer. Please check if I got your intentions right.
    – Doc Brown
    yesterday










  • There is no indication in the original post that a database is involved. So claiming that it assumes that Offer1 is already in the database is bizarre.
    – Winston Ewert
    yesterday






  • 1




    @WinstonEwert: there is a clear indication, you have to read the question more carefully. I did not realize it at the first read, too, but it is indeed what the OP is talking of.
    – Doc Brown
    yesterday












  • @mdfst13, I'm sorry I missed that. However, what the OP is saying is that the conditions are sometimes in a database and sometimes in the domain model. Your answer is perfectly fine for the first case, and irreverently in the second. If you'll edit your answer to clarify that point, I'll remove my hasty downvote.
    – Winston Ewert
    yesterday
















I tool the freedom to improve some minor details in your answer. Please check if I got your intentions right.
– Doc Brown
yesterday




I tool the freedom to improve some minor details in your answer. Please check if I got your intentions right.
– Doc Brown
yesterday












There is no indication in the original post that a database is involved. So claiming that it assumes that Offer1 is already in the database is bizarre.
– Winston Ewert
yesterday




There is no indication in the original post that a database is involved. So claiming that it assumes that Offer1 is already in the database is bizarre.
– Winston Ewert
yesterday




1




1




@WinstonEwert: there is a clear indication, you have to read the question more carefully. I did not realize it at the first read, too, but it is indeed what the OP is talking of.
– Doc Brown
yesterday






@WinstonEwert: there is a clear indication, you have to read the question more carefully. I did not realize it at the first read, too, but it is indeed what the OP is talking of.
– Doc Brown
yesterday














@mdfst13, I'm sorry I missed that. However, what the OP is saying is that the conditions are sometimes in a database and sometimes in the domain model. Your answer is perfectly fine for the first case, and irreverently in the second. If you'll edit your answer to clarify that point, I'll remove my hasty downvote.
– Winston Ewert
yesterday




@mdfst13, I'm sorry I missed that. However, what the OP is saying is that the conditions are sometimes in a database and sometimes in the domain model. Your answer is perfectly fine for the first case, and irreverently in the second. If you'll edit your answer to clarify that point, I'll remove my hasty downvote.
– Winston Ewert
yesterday


















draft saved

draft discarded




















































Thanks for contributing an answer to Software Engineering Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f384509%2fis-a-unit-test-considered-brittle-if-it-fails-when-the-business-logic-changes%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

What visual should I use to simply compare current year value vs last year in Power BI desktop

How to ignore python UserWarning in pytest?

Alexandru Averescu