2009-11-16 12 views
10

This question करीब है, लेकिन फिर भी मैं नहीं चाहता हूं। मैं एक सामान्य तरीके से जोर देना चाहता हूं कि दो बीन वस्तुओं समकक्ष हैं। यदि वे नहीं हैं, तो मुझे एक बूलियन "बराबर" या "बराबर नहीं" के बजाय अंतर को समझाते हुए एक विस्तृत त्रुटि संदेश चाहिए।जोर दें कि दो जावा बीन्स बराबर हैं

+3

आपको यह ब्लॉग प्रविष्टि प्रबुद्ध हो सकता है http://blogs.atlassian.com/developer/2009/06/how_hamcrest_can_save_your_sou.html – Chii

+1

@Chii: किसी भी कारण से आपने इसे टिप्पणी के रूप में क्यों पोस्ट किया? यह एक अच्छा जवाब है! –

+2

यहां मेटा-समस्या है: आप "समान", "बराबर" और "समकक्ष" को भ्रमित कर रहे हैं, बस हर किसी की तरह। – bendin

उत्तर

11

मैं सुझाव है कि आप unitils का उपयोग पुस्तकालय:

http://www.unitils.org/tutorial-reflectionassert.html

 
public class User { 

    private long id; 
    private String first; 
    private String last; 

    public User(long id, String first, String last) { 
     this.id = id; 
     this.first = first; 
     this.last = last; 
    } 
} 
 
User user1 = new User(1, "John", "Doe"); 
User user2 = new User(1, "John", "Doe"); 
assertReflectionEquals(user1, user2); 

भी देखें:

+1

महान जवाब!, मुझे यह नहीं पता था, और प्रत्येक संपत्ति के लिए assertEquals का उपयोग कर इकाई लिखना इतना दर्द है –

+1

मुझे कहना है कि यह पुस्तकालय बहुत अच्छा है। और यदि परीक्षण विफल रहता है, तो यह रिपोर्ट करता है कि कौन से फ़ील्ड विफलता और उनके मूल्य क्या थे। अच्छा काम आदमी। –

0

चूंकि आपको संदर्भित प्रश्न में दिए गए उत्तरों को पसंद नहीं आया है, इसलिए प्रत्येक बीन में toXml विधि क्यों न करें, उन्हें एक XML फ़ाइल में बदलें और फिर तुलना करने के लिए xmlUnit का उपयोग करें।

आप यहाँ xml फ़ाइलें की तुलना में अधिक जानकारी प्राप्त कर सकते हैं:

Best way to compare 2 XML documents in Java

+0

मेरी एकमात्र चिंता यह है कि कुछ गुणों को toXml() का उपयोग करके बाहर रखा जाना चाहिए, यह बल देता है कि वह जानता है कि तुलना की जा रही है, अन्यथा आपकी टिप्पणी होगी अधिक सही हो। –

3

आप Commons Lang के ToStringBuilder का उपयोग पठनीय स्ट्रिंग में उन दोनों को परिवर्तित करने के लिए और फिर दोनों तारों पर assertEquals() उपयोग कर सकते हैं।

यदि आप एक्सएमएल पसंद करते हैं, तो आप अपने बीन को एक्सएमएल में बदलने के लिए java.lang.XMLEncoder का उपयोग कर सकते हैं और फिर दो एक्सएमएल दस्तावेज़ों की तुलना कर सकते हैं।

व्यक्तिगत रूप से, मैं ToStringBuilder पसंद करता हूं क्योंकि यह आपको फ़ॉर्मेटिंग पर अधिक नियंत्रण देता है और आपको झूठी नकारात्मकताओं से बचने के लिए तत्वों को सॉर्ट करने जैसी चीजों को करने की अनुमति देता है।

मैं सुझाव देता हूं कि बीन के प्रत्येक क्षेत्र को एक अलग पंक्ति में डालने का सुझाव दिया जाए ताकि उन्हें तुलना करने के लिए इसे और अधिक सरल बनाया जा सके (see my blog for details)।

+0

बढ़िया, मुझे इसके बारे में पता नहीं था। असल में, मुझे इस तरह कुछ बुरी तरह की जरूरत है। धन्यवाद मित्र। –

0

आप वास्तव में समानता का दावा नहीं कर रहे हैं, और अधिक "diff" कर रहे हैं। जाहिर है, "समान" का अर्थ प्रत्येक प्रकार के लिए विशेष तर्क पर निर्भर करता है, और अंतर का प्रतिनिधित्व भी भिन्न हो सकता है। इस आवश्यकता के बीच एक बड़ा अंतर और पारंपरिक बराबर() आमतौर पर बराबर होता है (जैसे ही पहला अंतर देखा जाता है), आप हर क्षेत्र को आगे बढ़ाना और तुलना करना चाहते हैं।

मैं कुछ बराबर() पैटर्न का पुन: उपयोग करने पर विचार करता हूं, लेकिन मुझे संदेह है कि आपको अपना कोड लिखना होगा।

0

पहला quesion मुझे पूछना होगा कि क्या है, क्या आप बीन पर 'गहरी' बराबर करना चाहते हैं? क्या इसमें बच्चे सेम हैं जिन्हें परीक्षण करने की आवश्यकता है? आप बराबर विधि को ओवरराइड कर सकते हैं, लेकिन यह केवल एक बुलियन लौटाता है, ताकि आप 'तुलनित्र' बना सकें और जो कि बराबर नहीं था, उसके बारे में एक संदेश के साथ अपवाद फेंक सकता है।

निम्नलिखित उदाहरणों में, मैंने बराबर विधि को लागू करने के कुछ तरीके सूचीबद्ध किए हैं।

यदि आप यह देखना चाहते हैं कि वे एक ही ऑब्जेक्ट उदाहरण हैं, तो ऑब्जेक्ट से सामान्य बराबर विधि आपको बताएगी।

objectA.equals(objectB); 

यदि आप एक ग्राहक लिखना चाहते हैं की जाँच करने के लिए एक वस्तु के सभी सदस्य varibles उन्हें बराबर तो आप इस तरह बराबरी विधि ओवरराइड कर सकते हैं बनाने कि विधि ... के बराबर होती है

/** 
    * Method to check the following... 
    * <br> 
    * <ul> 
    * <li>getTitle</li> 
    * <li>getInitials</li> 
    * <li>getForename</li> 
    * <li>getSurname</li> 
    * <li>getSurnamePrefix</li> 
    * </ul> 
    * 
    * @see java.lang.Object#equals(java.lang.Object) 
    */ 
    @Override 
    public boolean equals(Object obj) 
    { 
     if ( (!compare(((ICustomer) obj).getTitle(), this.getTitle())) 
      || (!compare(((ICustomer) obj).getInitials(), this.getInitials())) 
      || (!compare(((ICustomer) obj).getForename(), this.getForename())) 
      || (!compare(((ICustomer) obj).getSurname(), this.getSurname())) 
      || (!compare(((ICustomer) obj).getSurnamePrefix(), this.getSurnamePrefix())) 
      || (!compare(((ICustomer) obj).getSalutation(), this.getSalutation())) ){ 
      return false; 
     } 
     return true; 
    } 

पिछले विकल्प बराबर विधि में सभी सदस्य varibles की जांच करने के लिए जावा प्रतिबिंब का उपयोग करना है। यह बहुत अच्छा है अगर आप वास्तव में अपने बीन गेट/सेट विधि के माध्यम से प्रत्येक सदस्य को विविधता से देखना चाहते हैं। यह नहीं होगा (मैं नहीं सोचता) आपको दो वस्तुओं की जांच के दौरान निजी memeber varibles की जांच करने की अनुमति देता है। (यदि आपके ऑब्जेक्ट मॉडल में गोलाकार निर्भरता नहीं है, तो ऐसा न करें, यह कभी वापस नहीं आएगा)

नोट: यह मेरा कोड नहीं है, यह ...

Java Reflection equals सार्वजनिक स्थिर बूलियन बराबर (वस्तु bean1, वस्तु bean2) { // संभाल तुच्छ मामलों अगर (bean1 == bean2) वापसी सच;

if (bean1 == null) 
return false; 

if (bean2 == null) 
return false; 

// Get the class of one of the parameters 
Class clazz = bean1.getClass(); 

// Make sure bean1 and bean2 are the same class 
if (!clazz.equals(bean2.getClass())) 
{ 
return false; 
} 

// Iterate through each field looking for differences 
Field[] fields = clazz.getDeclaredFields(); 
for (int i = 0; i < fields.length; i++) 
{ 
// setAccessible is great (encapsulation 
// purists will disagree), setting to true 
// allows reflection to have access to 
// private members. 
fields[i].setAccessible(true); 
try 
{ 
Object value1 = fields[i].get(bean1); 
Object value2 = fields[i].get(bean2); 

if ((value1 == null && value2 != null) || 
(value1 != null && value2 == null)) 
{ 
return false; 
} 

if (value1 != null && 
value2 != null && 
!value1.equals(value2)) 
{ 
return false; 
} 
} 
catch (IllegalArgumentException e) 
{ 
e.printStackTrace(); 
} 
catch (IllegalAccessException e) 
{ 
e.printStackTrace(); 
} 
} 

return true; 

एक बात यह है कि यह ऐसा नहीं करता है तो आप अंतर की वजह बताने के लिए है, लेकिन उस Log4J को संदेश के माध्यम से किया जा सकता है जब आप एक अनुभाग है कि बराबर नहीं है पाते हैं।

+0

-1 यह सिर्फ "एक अंतर है" कहता है लेकिन आपको कोई संकेत नहीं देता कि अंतर क्या हो सकता है। –

+0

तो वास्तविक कोड में, आप log4j पर एक संदेश डाल सकते हैं। –

+1

यूनिट परीक्षण के दौरान लॉग भी रखना आवश्यक नहीं होना चाहिए। असफल परीक्षण आपको बताए जाने वाले सभी को बताएंगे। –

1

मुझे लगता है कि सबसे सामान्य दृष्टिकोण बीन सदस्यों को प्रतिबिंबित करना और समानता के लिए एक-एक करके परीक्षण करना है। आम लैंग का EqualsBuilder एक अच्छी शुरुआत है और इसे आपकी आवश्यकताओं (स्रोत स्तर पर) को अनुकूलित करने के लिए एक बड़ा सौदा नहीं होना चाहिए (बराबर परिणाम लौटने के बजाय मतभेदों की रिपोर्ट करना)।

+0

-1 यह एक विस्तृत त्रुटि संदेश नहीं देता है जो अलग है। –

+0

मैंने इसे भी इस्तेमाल किया लेकिन थोड़ी अलग के साथ। EqualsBuilder का उपयोग करने के बाद एक सार्थक त्रुटि संदेश भी प्राप्त करने के लिए। \t प्रतिबिंब Iquals मैं दो ToStringBuilder.reflectionToString पर एक जोर देता हूं (अंत में एक असफल (...) के साथ स्ट्रिंग को वास्तव में सफल होना चाहिए)। ग्रहण फिर दो वस्तुओं के बीच अंतर को हाइलाइट करेगा। –

+0

@Aaron - मुझे पता है, और यही कारण है कि मैंने इक्वाल्सबिल्डर कोड को अनुकूलित करने का सुझाव दिया। –

0

मुझे लगता है कि दोनों बीन्स एक ही प्रकार के हैं, इस मामले में केवल सदस्य परिवर्तनीय मान बीन उदाहरणों में भिन्न होंगे।

एक उपयोग वर्ग (निजी सीटीओआर के साथ सार्वजनिक स्थिर फाइनल) को परिभाषित करें, कहें, बीनएएसएसर्ट एक्वाल्स। प्रत्येक बीन में प्रत्येक सदस्य चर के मान प्राप्त करने के लिए जावा प्रतिबिंब का उपयोग करें। फिर विभिन्न बीन्स में एक ही सदस्य चर के लिए मानों के बीच बराबर() करें। यदि समानता विफल हो जाती है, तो फ़ील्ड नाम का उल्लेख करें।

नोट: सदस्य चर आमतौर पर निजी होते हैं, इसलिए आपको अस्थायी रूप से निजी सदस्यों की पहुंच को बदलने के लिए प्रतिबिंब का उपयोग करना होगा।

साथ ही, निर्भर करता है कि ठीक कणों का आप दावा काम करना चाहते हैं, तो आपको निम्न पर विचार करना चाहिए: सेम वर्ग लेकिन सभी सुपर-क्लास में

  1. समानता के सदस्य चर नहीं।

  2. एरे में तत्वों की समानता, यदि सदस्य चर प्रकार सरणी है।

  3. बीन्स में दिए गए किसी सदस्य के दो मूल्यों के लिए, आप value1.equals (value2) के बजाय BeanAssertEquals.assertEquals (value1, value2) करने पर विचार कर सकते हैं।

0

(ऊपर Andreas_D को मेरी टिप्पणी पर बनाने के लिए)

/** Asserts two objects are equals using a reflective equals. 
* 
* @param message The message to display. 
* @param expected The expected result. 
* @param actual The actual result 
*/ 
public static void assertReflectiveEquals(final String message, 
     final Object expected, final Object actual) { 
    if (!EqualsBuilder.reflectionEquals(expected, actual)) { 
     assertEquals(message, 
       reflectionToString(expected, ToStringStyle.SHORT_PREFIX_STYLE), 
       reflectionToString(actual, ToStringStyle.SHORT_PREFIX_STYLE)); 
     fail(message + "expected: <" + expected + "> actual: <" + actual + ">"); 
    } 
} 

यह मैं क्या उपयोग है, और मेरा मानना ​​है कि यह सभी बुनियादी जरूरतों को पूरा करती। प्रतिबिंबित ToString पर जोर देकर ग्रहण अंतर को हाइलाइट करेगा।

जबकि Hamcrest एक बहुत अच्छा संदेश प्रदान कर सकता है, इसमें एक अच्छा सौदा कम कोड शामिल है।

11
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs; 
import static org.junit.Assert.assertThat; 

@Test 
public void beansAreTheSame(){ 
    MyDomianClass bean1 = new MyDomainClass(); 
    MyDomianClass bean2 = new MyDomainClass(); 
    //TODO - some more test logic 

    assertThat(bean1, samePropertyValuesAs(bean2)); 
} 
+0

इसे और अधिक दृश्यता की आवश्यकता है! – Stefan

1

इकाई इस परीक्षण के लिए JUnit और Mockito का उपयोग कर ReflectionEquals के साथ किया जा सकता है। निम्न तरीके से कार्यान्वित करते समय, यह ऑब्जेक्ट्स के जेएसओएन प्रस्तुतियों को डंप करेगा जब कोई फ़ील्ड बराबर नहीं है जिससे आपत्तिजनक अंतर को ढूंढना आसान हो जाता है।

import static org.junit.Assert.assertThat; 
import org.mockito.internal.matchers.apachecommons.ReflectionEquals; 

assertThat("Validating field equivalence of objects", expectedObjectValues, new ReflectionEquals(actualObjectValues)); 
1

आप इस तरह सभी क्षेत्रों सेट कर सकते हैं:

import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.allOf; 
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty; 
import static org.hamcrest.Matchers.is; 

@Test 
public void test_returnBean(){ 

    arrange(); 

    MyBean myBean = act(); 

    assertThat(myBean, allOf(hasProperty("id",   is(7L)), 
          hasProperty("name",  is("testName1")), 
          hasProperty("description", is("testDesc1")))); 
} 
0

xtendbeans library इस संदर्भ में ब्याज की हो सकता है:

AssertBeans.assertEqualBeans(expectedBean, actualBean); 

यह एक JUnit का उत्पादन ComparisonFailure ला:

expected: 
    new Person => [ 
     firstName = 'Homer' 
     lastName = 'Simpson' 
     address = new Address => [ 
      street = '742 Evergreen Terrace' 
      city = 'SpringField' 
     ] 
    ] 
but was: 
    new Person => [ 
     firstName = 'Marge' 
     lastName = 'Simpson' 
     address = new Address => [ 
      street = '742 Evergreen Terrace Road' 
      city = 'SpringField' 
     ] 
    ] 
String beanAsLiteralText = new XtendBeanGenerator().getExpression(yourBean) 

इस पुस्तकालय के साथ आप कॉपी/इसके लिए एक (Xtend) स्रोत वर्ग में चिपकाने के लिए ऊपर वाक्य रचना वैध वस्तु प्रवर्तन कोड टुकड़ा का उपयोग कर सकते हैं:आप भी इसे इस्तेमाल कर सकते हैं बस अन्य प्रयोजनों के लिए शाब्दिक प्रतिनिधित्व प्राप्त करने के लिए expectedBean, लेकिन आपको यह नहीं करना है, यह पूरी तरह से Xtend के बिना भी उपयोग किया जा सकता है।

संबंधित मुद्दे