<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://www.dotnetzone.gr:443/cs/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>.NET Framework</title><link>https://www.dotnetzone.gr:443/cs/forums/14/ShowForum.aspx</link><description>Θέματα για threading, remoting, reflection, exception handling, security, regex κλπ.</description><dc:language>el</dc:language><generator>CommunityServer 2.1 SP3 (Build: 20423.1)</generator><item><title>State and behavior testing στο ίδιο τεστ</title><link>https://www.dotnetzone.gr:443/cs/forums/thread/72236.aspx</link><pubDate>Sun, 03 Mar 2013 23:41:08 GMT</pubDate><guid isPermaLink="false">2622095e-976c-431a-859e-16783ec7ecd7:72236</guid><dc:creator>xabikos</dc:creator><slash:comments>0</slash:comments><comments>https://www.dotnetzone.gr:443/cs/forums/thread/72236.aspx</comments><wfw:commentRss>https://www.dotnetzone.gr:443/cs/forums/commentrss.aspx?SectionID=14&amp;PostID=72236</wfw:commentRss><description>Στην προσπάθεια που κάνω να βελτιώσω τον τρόπο που γράφω τεστ για τον κώδικα δεν μπορώ να αποφασίσω με σιγουριά πως ακριβώς πρέπει να γράφεται ένα τεστ. Σύμφωνα με αυτό που θεωρείται best practice το τεστ πρέπει να αφορά και να τεστάρει ένα και μόνο πράγμα. Έτσι δεν ξέρω αν το να τεστάρω τόσο την κατάσταση-αποτέλεσμα (state) όσο και την συμπεριφορά (behavior) του συστήματος στο ίδιο τεστ δεν είναι καλή πρακτική. &lt;br&gt;Για να γίνω πιο κατανοητός θα παραθέσω ένα παράδειγμα με κώδικα.&lt;br&gt;&lt;br&gt;&lt;table style="background-color:#f2f2f2;border:solid 1px #e5e5e5;" border="0" cellpadding="0" cellspacing="0" width="100%"&gt;&lt;tr style="vertical-align:top;line-height:normal;"&gt;&lt;td style="width:40px;text-align:right;"&gt;&lt;pre style="font-family:courier new;font-size:11px;color:gray;margin:0px;padding:2px;border-right:solid 1px #e7e7e7;"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 &lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style="margin:0px;padding:2px;padding-left:8px;"&gt;&lt;span style="color:Black;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;&lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;class&lt;/span&gt; UsersService
    {
        &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;readonly&lt;/span&gt; IUnitOfWorkFactory _unitOfWorkFactory;
        &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;readonly&lt;/span&gt; IUsersRespository _repository;

        &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;public&lt;/span&gt; UsersService(IUnitOfWorkFactory unitOfWorkFactory, IUsersRespository repository)
        {
            _unitOfWorkFactory &lt;span style="color:Red;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;=&lt;/span&gt; unitOfWorkFactory;
            _repository &lt;span style="color:Red;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;=&lt;/span&gt; repository;
        }

       &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;long&lt;/span&gt; Insert(User user)
        {
            &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;using&lt;/span&gt; (var uow &lt;span style="color:Red;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;=&lt;/span&gt; _unitOfWorkFactory.Create())
            {
                _repository.InsertOrUpdate(user);
                    uow.Commit();
                    &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;return&lt;/span&gt; user.Id;
                
            }
        }

    }

    &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;interface&lt;/span&gt; IUsersRespository
    {
        &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;void&lt;/span&gt; InsertOrUpdate(User user);
    }

    &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;interface&lt;/span&gt; IUnitOfWorkFactory
    {
        IUnitOfWork Create();
    }

    &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;interface&lt;/span&gt; IUnitOfWork : IDisposable
    {
        &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;void&lt;/span&gt; Commit();
    }&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br&gt;Και θέλουμε να τεστάρουμε την μέθοδο insert του service. Αυτό που μπορώ να σκεφτώ είναι δυο προσεγγίσεις. Η πρώτη σε μια μέθοδο τεστάρουμε τόσο την σωστή αλληλεπίδραση μεταξύ των objects αλλά και το αποτέλεσμα που επιστρέφει η μέθοδος. Ο κώδικας μοιάζει με τον παρακάτω:&lt;br&gt;&lt;br&gt;&lt;table style="background-color:#f2f2f2;border:solid 1px #e5e5e5;" border="0" cellpadding="0" cellspacing="0" width="100%"&gt;&lt;tr style="vertical-align:top;line-height:normal;"&gt;&lt;td style="width:40px;text-align:right;"&gt;&lt;pre style="font-family:courier new;font-size:11px;color:gray;margin:0px;padding:2px;border-right:solid 1px #e7e7e7;"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 &lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style="margin:0px;padding:2px;padding-left:8px;"&gt;&lt;span style="color:Black;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;&lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;void&lt;/span&gt; TestInsert_ValidUser_ReturnsId()
        {
            &lt;span style="color:Green;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;//Arrange&lt;/span&gt;
            _mockedRepository.Setup(r =&amp;gt; r.InsertOrUpdate(It.IsAny&amp;lt;User&amp;gt;())).Callback((User u) =&amp;gt; { u.Id++; });
            User newUser &lt;span style="color:Red;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;new&lt;/span&gt; User {UserName &lt;span style="color:Red;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;=&lt;/span&gt; &lt;span style="color:#666666;background-color:#e4e4e4;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;"username"&lt;/span&gt;, Password &lt;span style="color:Red;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;=&lt;/span&gt; &lt;span style="color:#666666;background-color:#e4e4e4;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;"Password"&lt;/span&gt;};

            &lt;span style="color:Green;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;//Act&lt;/span&gt;
            var result &lt;span style="color:Red;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;=&lt;/span&gt; _service.Insert(newUser);

            &lt;span style="color:Green;background-color:Transparent;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;//Assert&lt;/span&gt;
            Assert.AreNotEqual(0, result, &lt;span style="color:#666666;background-color:#e4e4e4;font-family:Courier New;font-size:11px;font-weight:normal;"&gt;"Id not set"&lt;/span&gt;);
            _mockedUnitOfWorkFactory.Verify(uof =&amp;gt; uof.Create(), Times.AtLeast(1));
            _mockedRepository.Verify(r =&amp;gt; r.InsertOrUpdate(It.IsAny&amp;lt;User&amp;gt;()), Times.Once());
            _mockedUnitOfWork.Verify(uow=&amp;gt;uow.Commit(), Times.Once());
        }&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br&gt;Έτσι σε αυτή την μέθοδο τεστάρουμε τόσο ότι η οντότητα απέκτησε κάποιο Id διαφορετικό από το 0 (state) όσο και το ότι κλήθηκαν μέθοδοι στα άλλα αντικείμενα (behavior).&lt;br&gt;&lt;br&gt;Η άλλη προσέγγιση που μπορώ να σκεφτώ είναι χωρίζουμε το παραπάνω τεστ σε τέσσερις διαφορετικές μεθόδους που η κάθε μία από αυτή θα είναι υπεύθυνη για έναν και μόνο έλεγχο.&lt;br&gt;Για παράδειγμα η μια θα ελέγχει για το Id η άλλη ότι κλήθηκε η μέθοδος create τουλάχιστον μια φορά κ.ο.κ.&lt;br&gt;Προσωπικά προτιμώ την πρώτη προσέγγιση μιας δεν υπάρχουν τόσες πολλές μέθοδοι για συντήρηση. Από την άλλη βέβαια η συγκεκριμένη μέθοδος εξαρτάται πάρα πολύ από την συγκεκριμένη υλοποίηση και σε μια αλλαγή θα πρέπει να αλλάξει αντίστοιχα και το τεστ.&lt;br&gt;&lt;br&gt;Περιμένω να ακούσω γνώμες και οποιεσδήποτε παρατηρήσεις πάνω στο θέμα.&lt;br&gt;&lt;br&gt;</description></item></channel></rss>